diff options
Diffstat (limited to 'scene')
442 files changed, 12532 insertions, 11907 deletions
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp index 0f98fad824..dfc08583f2 100644 --- a/scene/2d/animated_sprite_2d.cpp +++ b/scene/2d/animated_sprite_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -105,214 +105,6 @@ Rect2 AnimatedSprite2D::_get_rect() const { return Rect2(ofs, s); } -void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) { - E->get().frames.insert(p_at_pos, p_frame); - } else { - E->get().frames.push_back(p_frame); - } - - emit_changed(); -} - -int SpriteFrames::get_frame_count(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); - - return E->get().frames.size(); -} - -void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - E->get().frames.remove(p_idx); - emit_changed(); -} - -void SpriteFrames::clear(const StringName &p_anim) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - - E->get().frames.clear(); - emit_changed(); -} - -void SpriteFrames::clear_all() { - animations.clear(); - add_animation("default"); -} - -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(); -} - -bool SpriteFrames::has_animation(const StringName &p_anim) const { - return animations.has(p_anim); -} - -void SpriteFrames::remove_animation(const StringName &p_anim) { - animations.erase(p_anim); -} - -void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) { - ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'."); - ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists."); - - Anim anim = animations[p_prev]; - animations.erase(p_prev); - animations[p_next] = anim; -} - -Vector<String> SpriteFrames::_get_animation_list() const { - Vector<String> ret; - List<StringName> al; - get_animation_list(&al); - for (List<StringName>::Element *E = al.front(); E; E = E->next()) { - ret.push_back(E->get()); - } - - return ret; -} - -void SpriteFrames::get_animation_list(List<StringName> *r_animations) const { - for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - r_animations->push_back(E->key()); - } -} - -Vector<String> SpriteFrames::get_animation_names() const { - Vector<String> names; - for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - names.push_back(E->key()); - } - names.sort(); - return names; -} - -void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { - ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - E->get().speed = p_fps; -} - -float SpriteFrames::get_animation_speed(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); - return E->get().speed; -} - -void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) { - Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); - E->get().loop = p_loop; -} - -bool SpriteFrames::get_animation_loop(const StringName &p_anim) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist."); - return E->get().loop; -} - -void SpriteFrames::_set_frames(const Array &p_frames) { - clear_all(); - Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default); - ERR_FAIL_COND(!E); - - E->get().frames.resize(p_frames.size()); - for (int i = 0; i < E->get().frames.size(); i++) { - E->get().frames.write[i] = p_frames[i]; - } -} - -Array SpriteFrames::_get_frames() const { - return Array(); -} - -Array SpriteFrames::_get_animations() const { - Array anims; - for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { - Dictionary d; - d["name"] = E->key(); - d["speed"] = E->get().speed; - d["loop"] = E->get().loop; - Array frames; - for (int i = 0; i < E->get().frames.size(); i++) { - frames.push_back(E->get().frames[i]); - } - d["frames"] = frames; - anims.push_back(d); - } - - return anims; -} - -void SpriteFrames::_set_animations(const Array &p_animations) { - animations.clear(); - for (int i = 0; i < p_animations.size(); i++) { - Dictionary d = p_animations[i]; - - ERR_CONTINUE(!d.has("name")); - ERR_CONTINUE(!d.has("speed")); - ERR_CONTINUE(!d.has("loop")); - ERR_CONTINUE(!d.has("frames")); - - Anim anim; - anim.speed = d["speed"]; - anim.loop = d["loop"]; - Array frames = d["frames"]; - for (int j = 0; j < frames.size(); j++) { - RES res = frames[j]; - anim.frames.push_back(res); - } - - animations[d["name"]] = anim; - } -} - -void SpriteFrames::_bind_methods() { - ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation); - ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation); - ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation); - ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation); - - ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names); - - ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed); - ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed); - - ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop); - ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop); - - ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1)); - ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count); - ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame); - ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame); - ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame); - ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear); - ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all); - - ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames); - ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility - - ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations); - ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations); - - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility -} - -SpriteFrames::SpriteFrames() { - add_animation(SceneStringNames::get_singleton()->_default); -} - void AnimatedSprite2D::_validate_property(PropertyInfo &property) const { if (!frames.is_valid()) { return; @@ -409,7 +201,7 @@ void AnimatedSprite2D::_notification(int p_what) { } update(); - _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -477,7 +269,7 @@ void AnimatedSprite2D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { set_frame(frame); } - _change_notify(); + notify_property_list_changed(); _reset_timeout(); update(); update_configuration_warning(); @@ -510,7 +302,7 @@ void AnimatedSprite2D::set_frame(int p_frame) { frame = p_frame; _reset_timeout(); update(); - _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -546,7 +338,6 @@ void AnimatedSprite2D::set_offset(const Point2 &p_offset) { offset = p_offset; update(); item_rect_changed(); - _change_notify("offset"); } Point2 AnimatedSprite2D::get_offset() const { @@ -573,8 +364,7 @@ bool AnimatedSprite2D::is_flipped_v() const { void AnimatedSprite2D::_res_changed() { set_frame(frame); - _change_notify("frame"); - _change_notify("animation"); + update(); } @@ -592,6 +382,7 @@ bool AnimatedSprite2D::_is_playing() const { } void AnimatedSprite2D::play(const StringName &p_animation, const bool p_backwards) { + ERR_FAIL_NULL_MSG(frames, "Can't play AnimatedSprite2D without a valid SpriteFrames resource."); backwards = p_backwards; if (p_animation) { @@ -642,7 +433,7 @@ void AnimatedSprite2D::set_animation(const StringName &p_animation) { animation = p_animation; _reset_timeout(); set_frame(0); - _change_notify(); + notify_property_list_changed(); update(); } @@ -654,7 +445,7 @@ String AnimatedSprite2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (frames.is_null()) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -712,15 +503,4 @@ void AnimatedSprite2D::_bind_methods() { } AnimatedSprite2D::AnimatedSprite2D() { - centered = true; - hflip = false; - vflip = false; - - frame = 0; - speed_scale = 1.0f; - playing = false; - backwards = false; - animation = "default"; - timeout = 0; - is_over = false; } diff --git a/scene/2d/animated_sprite_2d.h b/scene/2d/animated_sprite_2d.h index fddbf39be2..14ecb18866 100644 --- a/scene/2d/animated_sprite_2d.h +++ b/scene/2d/animated_sprite_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,97 +32,27 @@ #define ANIMATED_SPRITE_2D_H #include "scene/2d/node_2d.h" +#include "scene/resources/sprite_frames.h" #include "scene/resources/texture.h" -class SpriteFrames : public Resource { - GDCLASS(SpriteFrames, Resource); - - struct Anim { - float speed; - bool loop; - Vector<Ref<Texture2D>> frames; - - Anim() { - loop = true; - speed = 5; - } - }; - - Map<StringName, Anim> animations; - - Array _get_frames() const; - void _set_frames(const Array &p_frames); - - Array _get_animations() const; - void _set_animations(const Array &p_animations); - - Vector<String> _get_animation_list() const; - -protected: - static void _bind_methods(); - -public: - void add_animation(const StringName &p_anim); - bool has_animation(const StringName &p_anim) const; - void remove_animation(const StringName &p_anim); - void rename_animation(const StringName &p_prev, const StringName &p_next); - - void get_animation_list(List<StringName> *r_animations) const; - Vector<String> get_animation_names() const; - - void set_animation_speed(const StringName &p_anim, float p_fps); - float get_animation_speed(const StringName &p_anim) const; - - void set_animation_loop(const StringName &p_anim, bool p_loop); - bool get_animation_loop(const StringName &p_anim) const; - - void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1); - int get_frame_count(const StringName &p_anim) const; - _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const { - const Map<StringName, Anim>::Element *E = animations.find(p_anim); - ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist."); - ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); - if (p_idx >= E->get().frames.size()) { - return Ref<Texture2D>(); - } - - return E->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."); - ERR_FAIL_COND(p_idx < 0); - if (p_idx >= E->get().frames.size()) { - return; - } - E->get().frames.write[p_idx] = p_frame; - } - void remove_frame(const StringName &p_anim, int p_idx); - void clear(const StringName &p_anim); - void clear_all(); - - SpriteFrames(); -}; - class AnimatedSprite2D : public Node2D { GDCLASS(AnimatedSprite2D, Node2D); Ref<SpriteFrames> frames; - bool playing; - bool backwards; - StringName animation; - int frame; - float speed_scale; + bool playing = false; + bool backwards = false; + StringName animation = "default"; + int frame = 0; + float speed_scale = 1.0f; - bool centered; + bool centered = true; Point2 offset; - bool is_over; - float timeout; + bool is_over = false; + float timeout = 0.0; - bool hflip; - bool vflip; + bool hflip = false; + bool vflip = false; void _res_changed(); diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index d51ee3f9a8..49d1654e3f 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -590,13 +590,13 @@ void Area2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_body_inout"), &Area2D::_body_inout); ClassDB::bind_method(D_METHOD("_area_inout"), &Area2D::_area_inout); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node2D"))); - ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); - ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"))); ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area2D"))); @@ -627,20 +627,8 @@ void Area2D::_bind_methods() { Area2D::Area2D() : CollisionObject2D(PhysicsServer2D::get_singleton()->area_create(), true) { - space_override = SPACE_OVERRIDE_DISABLED; set_gravity(98); set_gravity_vector(Vector2(0, 1)); - gravity_is_point = false; - gravity_distance_scale = 0; - linear_damp = 0.1; - angular_damp = 1; - locked = false; - priority = 0; - monitoring = false; - monitorable = false; - collision_mask = 1; - collision_layer = 1; - audio_bus_override = false; set_monitoring(true); set_monitorable(true); } diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index 01426db999..39b022fd2c 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,19 +47,19 @@ public: }; private: - SpaceOverride space_override; + SpaceOverride space_override = SPACE_OVERRIDE_DISABLED; Vector2 gravity_vec; real_t gravity; - bool gravity_is_point; - real_t gravity_distance_scale; - real_t linear_damp; - real_t angular_damp; - uint32_t collision_mask; - uint32_t collision_layer; - int priority; - bool monitoring; - bool monitorable; - bool locked; + bool gravity_is_point = false; + real_t gravity_distance_scale = 0.0; + real_t linear_damp = 0.1; + real_t angular_damp = 1.0; + uint32_t collision_mask = 1; + uint32_t collision_layer = 1; + int priority = 0; + bool monitoring = false; + bool monitorable = false; + bool locked = false; void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape); @@ -67,8 +67,8 @@ private: void _body_exit_tree(ObjectID p_id); struct ShapePair { - int body_shape; - int area_shape; + int body_shape = 0; + int area_shape = 0; bool operator<(const ShapePair &p_sp) const { if (body_shape == p_sp.body_shape) { return area_shape < p_sp.area_shape; @@ -85,8 +85,8 @@ private: }; struct BodyState { - int rc; - bool in_tree; + int rc = 0; + bool in_tree = false; VSet<ShapePair> shapes; }; @@ -98,8 +98,8 @@ private: void _area_exit_tree(ObjectID p_id); struct AreaShapePair { - int area_shape; - int self_shape; + int area_shape = 0; + int self_shape = 0; bool operator<(const AreaShapePair &p_sp) const { if (area_shape == p_sp.area_shape) { return self_shape < p_sp.self_shape; @@ -116,15 +116,15 @@ private: }; struct AreaState { - int rc; - bool in_tree; + int rc = 0; + bool in_tree = false; VSet<AreaShapePair> shapes; }; Map<ObjectID, AreaState> area_map; void _clear_monitoring(); - bool audio_bus_override; + bool audio_bus_override = false; StringName audio_bus; protected: diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp index 9bd716aeaa..6d8d6058eb 100644 --- a/scene/2d/audio_stream_player_2d.cpp +++ b/scene/2d/audio_stream_player_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,14 +35,14 @@ #include "scene/main/window.h" void AudioStreamPlayer2D::_mix_audio() { - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade_out)) { return; } - if (setseek >= 0.0) { - stream_playback->start(setseek); - setseek = -1.0; //reset seek + if (setseek.get() >= 0.0) { + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek } //get data @@ -57,7 +57,8 @@ void AudioStreamPlayer2D::_mix_audio() { stream_playback->mix(buffer, pitch_scale, buffer_size); //write all outputs - for (int i = 0; i < output_count; i++) { + int oc = output_count.get(); + for (int i = 0; i < oc; i++) { Output current = outputs[i]; //see if current output exists, to keep volume ramp @@ -130,14 +131,14 @@ void AudioStreamPlayer2D::_mix_audio() { prev_outputs[i] = current; } - prev_output_count = output_count; + prev_output_count = oc; //stream is no longer active, disable this. if (!stream_playback->is_playing()) { - active = false; + active.clear(); } - output_ready = false; + output_ready.clear(); stream_paused_fade_in = false; stream_paused_fade_out = false; } @@ -168,7 +169,7 @@ void AudioStreamPlayer2D::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { //update anything related to position first, if possible of course - if (!output_ready) { + if (!output_ready.is_set()) { List<Viewport *> viewports; Ref<World2D> world_2d = get_world_2d(); ERR_FAIL_COND(world_2d.is_null()); @@ -240,24 +241,20 @@ void AudioStreamPlayer2D::_notification(int p_what) { } } - output_count = new_output_count; - output_ready = true; + output_count.set(new_output_count); + output_ready.set(); } //start playing if requested - if (setplay >= 0.0) { - setseek = setplay; - active = true; - setplay = -1; - //do not update, this makes it easier to animate (will shut off otherwise) - //_change_notify("playing"); //update property in editor + if (setplay.get() >= 0.0) { + setseek.set(setplay.get()); + active.set(); + setplay.set(-1); } //stop playing if no longer active - if (!active) { + if (!active.is_set()) { set_physics_process_internal(false); - //do not update, this makes it easier to animate (will shut off otherwise) - //_change_notify("playing"); //update property in editor emit_signal("finished"); } } @@ -271,8 +268,8 @@ void AudioStreamPlayer2D::set_stream(Ref<AudioStream> p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; + active.clear(); + setseek.set(-1); } if (p_stream.is_valid()) { @@ -315,30 +312,29 @@ void AudioStreamPlayer2D::play(float p_from_pos) { } if (stream_playback.is_valid()) { - active = true; - setplay = p_from_pos; - output_ready = false; + setplay.set(p_from_pos); + output_ready.clear(); set_physics_process_internal(true); } } void AudioStreamPlayer2D::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer2D::stop() { if (stream_playback.is_valid()) { - active = false; + active.clear(); set_physics_process_internal(false); - setplay = -1; + setplay.set(-1); } } bool AudioStreamPlayer2D::is_playing() const { if (stream_playback.is_valid()) { - return active; // && stream_playback->is_playing(); + return active.is_set() || setplay.get() >= 0; } return false; @@ -346,6 +342,10 @@ bool AudioStreamPlayer2D::is_playing() const { float AudioStreamPlayer2D::get_playback_position() { if (stream_playback.is_valid()) { + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; + } return stream_playback->get_playback_position(); } @@ -385,7 +385,7 @@ void AudioStreamPlayer2D::_set_playing(bool p_enable) { } bool AudioStreamPlayer2D::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { @@ -404,7 +404,7 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &property) const { } void AudioStreamPlayer2D::_bus_layout_changed() { - _change_notify(); + notify_property_list_changed(); } void AudioStreamPlayer2D::set_max_distance(float p_pixels) { @@ -503,21 +503,6 @@ void AudioStreamPlayer2D::_bind_methods() { } AudioStreamPlayer2D::AudioStreamPlayer2D() { - volume_db = 0; - pitch_scale = 1.0; - autoplay = false; - setseek = -1; - active = false; - output_count = 0; - prev_output_count = 0; - max_distance = 2000; - attenuation = 1; - setplay = -1; - output_ready = false; - area_mask = 1; - stream_paused = false; - stream_paused_fade_in = false; - stream_paused_fade_out = false; AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed)); } diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h index 4e236a367e..21f524c703 100644 --- a/scene/2d/audio_stream_player_2d.h +++ b/scene/2d/audio_stream_player_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_2D_H #define AUDIO_STREAM_PLAYER_2D_H +#include "core/templates/safe_refcount.h" #include "scene/2d/node_2d.h" #include "servers/audio/audio_stream.h" #include "servers/audio_server.h" @@ -47,32 +48,32 @@ private: struct Output { AudioFrame vol; - int bus_index; - Viewport *viewport; //pointer only used for reference to previous mix + int bus_index = 0; + Viewport *viewport = nullptr; //pointer only used for reference to previous mix }; Output outputs[MAX_OUTPUTS]; - volatile int output_count; - volatile bool output_ready; + SafeNumeric<int> output_count; + SafeFlag output_ready; //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks) Output prev_outputs[MAX_OUTPUTS]; - int prev_output_count; + int prev_output_count = 0; Ref<AudioStreamPlayback> stream_playback; Ref<AudioStream> stream; Vector<AudioFrame> mix_buffer; - volatile float setseek; - volatile bool active; - volatile float setplay; + SafeNumeric<float> setseek{ -1.0 }; + SafeFlag active; + SafeNumeric<float> setplay{ -1.0 }; - float volume_db; - float pitch_scale; - bool autoplay; - bool stream_paused; - bool stream_paused_fade_in; - bool stream_paused_fade_out; + float volume_db = 0.0; + float pitch_scale = 1.0; + bool autoplay = false; + bool stream_paused = false; + bool stream_paused_fade_in = false; + bool stream_paused_fade_out = false; StringName bus; void _mix_audio(); @@ -83,10 +84,10 @@ private: void _bus_layout_changed(); - uint32_t area_mask; + uint32_t area_mask = 1; - float max_distance; - float attenuation; + float max_distance = 2000.0; + float attenuation = 1.0; protected: void _validate_property(PropertyInfo &property) const override; diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index a36e0a86e1..539a66b881 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -93,8 +93,6 @@ void BackBufferCopy::_bind_methods() { } BackBufferCopy::BackBufferCopy() { - rect = Rect2(-100, -100, 200, 200); - copy_mode = COPY_MODE_RECT; _update_copy_mode(); } diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index b58034de19..6bdb3aaab2 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,8 +44,8 @@ public: }; private: - Rect2 rect; - CopyMode copy_mode; + Rect2 rect = Rect2(-100, -100, 200, 200); + CopyMode copy_mode = COPY_MODE_RECT; void _update_copy_mode(); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 0d09d21a71..01045502d5 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -63,11 +63,11 @@ void Camera2D::_update_scroll() { }; } -void Camera2D::_update_process_mode() { +void Camera2D::_update_process_callback() { if (Engine::get_singleton()->is_editor_hint()) { set_process_internal(false); set_physics_process_internal(false); - } else if (process_mode == CAMERA2D_PROCESS_IDLE) { + } else if (process_callback == CAMERA2D_PROCESS_IDLE) { set_process_internal(true); set_physics_process_internal(false); } else { @@ -104,31 +104,31 @@ Transform2D Camera2D::get_camera_transform() { if (!first) { if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { - if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint() && !h_offset_changed) { - camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_LEFT])); - camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_RIGHT])); + if (drag_horizontal_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_horizontal_offset_changed) { + camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[SIDE_LEFT])); + camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[SIDE_RIGHT])); } else { - if (h_ofs < 0) { - camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; + if (drag_horizontal_offset < 0) { + camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_RIGHT] * drag_horizontal_offset; } else { - camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; + camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_LEFT] * drag_horizontal_offset; } - h_offset_changed = false; + drag_horizontal_offset_changed = false; } - if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint() && !v_offset_changed) { - camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_TOP])); - camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_BOTTOM])); + if (drag_vertical_enabled && !Engine::get_singleton()->is_editor_hint() && !drag_vertical_offset_changed) { + camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[SIDE_TOP])); + camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[SIDE_BOTTOM])); } else { - if (v_ofs < 0) { - camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; + if (drag_vertical_offset < 0) { + camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[SIDE_BOTTOM] * drag_vertical_offset; } else { - camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; + camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[SIDE_TOP] * drag_vertical_offset; } - v_offset_changed = false; + drag_vertical_offset_changed = false; } } else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) { @@ -139,25 +139,25 @@ Transform2D Camera2D::get_camera_transform() { Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom); if (limit_smoothing_enabled) { - if (screen_rect.position.x < limit[MARGIN_LEFT]) { - camera_pos.x -= screen_rect.position.x - limit[MARGIN_LEFT]; + if (screen_rect.position.x < limit[SIDE_LEFT]) { + camera_pos.x -= screen_rect.position.x - limit[SIDE_LEFT]; } - if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) { - camera_pos.x -= screen_rect.position.x + screen_rect.size.x - limit[MARGIN_RIGHT]; + if (screen_rect.position.x + screen_rect.size.x > limit[SIDE_RIGHT]) { + camera_pos.x -= screen_rect.position.x + screen_rect.size.x - limit[SIDE_RIGHT]; } - if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) { - camera_pos.y -= screen_rect.position.y + screen_rect.size.y - limit[MARGIN_BOTTOM]; + if (screen_rect.position.y + screen_rect.size.y > limit[SIDE_BOTTOM]) { + camera_pos.y -= screen_rect.position.y + screen_rect.size.y - limit[SIDE_BOTTOM]; } - if (screen_rect.position.y < limit[MARGIN_TOP]) { - camera_pos.y -= screen_rect.position.y - limit[MARGIN_TOP]; + if (screen_rect.position.y < limit[SIDE_TOP]) { + camera_pos.y -= screen_rect.position.y - limit[SIDE_TOP]; } } if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) { - float c = smoothing * (process_mode == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); + real_t c = smoothing * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; @@ -172,26 +172,26 @@ Transform2D Camera2D::get_camera_transform() { Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); - float angle = get_global_transform().get_rotation(); + real_t angle = get_global_transform().get_rotation(); if (rotating) { screen_offset = screen_offset.rotated(angle); } Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom); - if (screen_rect.position.x < limit[MARGIN_LEFT]) { - screen_rect.position.x = limit[MARGIN_LEFT]; + if (screen_rect.position.x < limit[SIDE_LEFT]) { + screen_rect.position.x = limit[SIDE_LEFT]; } - if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT]) { - screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x; + if (screen_rect.position.x + screen_rect.size.x > limit[SIDE_RIGHT]) { + screen_rect.position.x = limit[SIDE_RIGHT] - screen_rect.size.x; } - if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM]) { - screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y; + if (screen_rect.position.y + screen_rect.size.y > limit[SIDE_BOTTOM]) { + screen_rect.position.y = limit[SIDE_BOTTOM] - screen_rect.size.y; } - if (screen_rect.position.y < limit[MARGIN_TOP]) { - screen_rect.position.y = limit[MARGIN_TOP]; + if (screen_rect.position.y < limit[SIDE_TOP]) { + screen_rect.position.y = limit[SIDE_TOP]; } if (offset != Vector2()) { @@ -247,7 +247,7 @@ void Camera2D::_notification(int p_what) { add_to_group(group_name); add_to_group(canvas_group_name); - _update_process_mode(); + _update_process_callback(); _update_scroll(); first = true; @@ -263,6 +263,7 @@ void Camera2D::_notification(int p_what) { viewport = nullptr; } break; +#ifdef TOOLS_ENABLED case NOTIFICATION_DRAW: { if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint()) { break; @@ -270,7 +271,7 @@ void Camera2D::_notification(int p_what) { if (screen_drawing_enabled) { Color area_axis_color(0.5, 0.42, 0.87, 0.63); - float area_axis_width = 1; + real_t area_axis_width = 1; if (is_current()) { area_axis_width = 3; area_axis_color.a = 0.83; @@ -295,7 +296,7 @@ void Camera2D::_notification(int p_what) { if (limit_drawing_enabled) { Color limit_drawing_color(1, 1, 0, 0.63); - float limit_drawing_width = 1; + real_t limit_drawing_width = 1; if (is_current()) { limit_drawing_color.a = 0.83; limit_drawing_width = 3; @@ -304,10 +305,10 @@ void Camera2D::_notification(int p_what) { Vector2 camera_origin = get_global_transform().get_origin(); Vector2 camera_scale = get_global_transform().get_scale().abs(); Vector2 limit_points[4] = { - (Vector2(limit[MARGIN_LEFT], limit[MARGIN_TOP]) - camera_origin) / camera_scale, - (Vector2(limit[MARGIN_RIGHT], limit[MARGIN_TOP]) - camera_origin) / camera_scale, - (Vector2(limit[MARGIN_RIGHT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale, - (Vector2(limit[MARGIN_LEFT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale + (Vector2(limit[SIDE_LEFT], limit[SIDE_TOP]) - camera_origin) / camera_scale, + (Vector2(limit[SIDE_RIGHT], limit[SIDE_TOP]) - camera_origin) / camera_scale, + (Vector2(limit[SIDE_RIGHT], limit[SIDE_BOTTOM]) - camera_origin) / camera_scale, + (Vector2(limit[SIDE_LEFT], limit[SIDE_BOTTOM]) - camera_origin) / camera_scale }; for (int i = 0; i < 4; i++) { @@ -317,7 +318,7 @@ void Camera2D::_notification(int p_what) { if (margin_drawing_enabled) { Color margin_drawing_color(0, 1, 1, 0.63); - float margin_drawing_width = 1; + real_t margin_drawing_width = 1; if (is_current()) { margin_drawing_width = 3; margin_drawing_color.a = 0.83; @@ -327,10 +328,10 @@ void Camera2D::_notification(int p_what) { 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]))), - inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))), - inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[MARGIN_BOTTOM]))), - 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_BOTTOM]))) + inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[SIDE_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[SIDE_TOP]))), + inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[SIDE_RIGHT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[SIDE_TOP]))), + inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[SIDE_RIGHT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[SIDE_BOTTOM]))), + inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[SIDE_LEFT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[SIDE_BOTTOM]))) }; Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space @@ -339,8 +340,8 @@ void Camera2D::_notification(int p_what) { draw_line(inv_transform.xform(margin_endpoints[i]), inv_transform.xform(margin_endpoints[(i + 1) % 4]), margin_drawing_color, margin_drawing_width); } } - } break; +#endif } } @@ -375,17 +376,17 @@ bool Camera2D::is_rotating() const { return rotating; } -void Camera2D::set_process_mode(Camera2DProcessMode p_mode) { - if (process_mode == p_mode) { +void Camera2D::set_process_callback(Camera2DProcessCallback p_mode) { + if (process_callback == p_mode) { return; } - process_mode = p_mode; - _update_process_mode(); + process_callback = p_mode; + _update_process_callback(); } -Camera2D::Camera2DProcessMode Camera2D::get_process_mode() const { - return process_mode; +Camera2D::Camera2DProcessCallback Camera2D::get_process_callback() const { + return process_callback; } void Camera2D::_make_current(Object *p_which) { @@ -425,15 +426,15 @@ void Camera2D::clear_current() { } } -void Camera2D::set_limit(Margin p_margin, int p_limit) { - ERR_FAIL_INDEX((int)p_margin, 4); - limit[p_margin] = p_limit; +void Camera2D::set_limit(Side p_side, int p_limit) { + ERR_FAIL_INDEX((int)p_side, 4); + limit[p_side] = p_limit; update(); } -int Camera2D::get_limit(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return limit[p_margin]; +int Camera2D::get_limit(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return limit[p_side]; } void Camera2D::set_limit_smoothing_enabled(bool enable) { @@ -445,15 +446,15 @@ bool Camera2D::is_limit_smoothing_enabled() const { return limit_smoothing_enabled; } -void Camera2D::set_drag_margin(Margin p_margin, float p_drag_margin) { - ERR_FAIL_INDEX((int)p_margin, 4); - drag_margin[p_margin] = p_drag_margin; +void Camera2D::set_drag_margin(Side p_side, real_t p_drag_margin) { + ERR_FAIL_INDEX((int)p_side, 4); + drag_margin[p_side] = p_drag_margin; update(); } -float Camera2D::get_drag_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return drag_margin[p_margin]; +real_t Camera2D::get_drag_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return drag_margin[p_side]; } Vector2 Camera2D::get_camera_position() const { @@ -476,15 +477,15 @@ void Camera2D::align() { Point2 current_camera_pos = get_global_transform().get_origin(); if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) { - if (h_ofs < 0) { - camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; + if (drag_horizontal_offset < 0) { + camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_RIGHT] * drag_horizontal_offset; } else { - camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; + camera_pos.x = current_camera_pos.x + screen_size.x * 0.5 * drag_margin[SIDE_LEFT] * drag_horizontal_offset; } - if (v_ofs < 0) { - camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; + if (drag_vertical_offset < 0) { + camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[SIDE_TOP] * drag_vertical_offset; } else { - camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; + camera_pos.y = current_camera_pos.y + screen_size.y * 0.5 * drag_margin[SIDE_BOTTOM] * drag_vertical_offset; } } else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) { camera_pos = current_camera_pos; @@ -493,7 +494,7 @@ void Camera2D::align() { _update_scroll(); } -void Camera2D::set_follow_smoothing(float p_speed) { +void Camera2D::set_follow_smoothing(real_t p_speed) { smoothing = p_speed; if (smoothing > 0 && !(is_inside_tree() && Engine::get_singleton()->is_editor_hint())) { set_process_internal(true); @@ -502,7 +503,7 @@ void Camera2D::set_follow_smoothing(float p_speed) { } } -float Camera2D::get_follow_smoothing() const { +real_t Camera2D::get_follow_smoothing() const { return smoothing; } @@ -518,47 +519,47 @@ Size2 Camera2D::_get_camera_screen_size() const { return get_viewport_rect().size; } -void Camera2D::set_h_drag_enabled(bool p_enabled) { - h_drag_enabled = p_enabled; +void Camera2D::set_drag_horizontal_enabled(bool p_enabled) { + drag_horizontal_enabled = p_enabled; } -bool Camera2D::is_h_drag_enabled() const { - return h_drag_enabled; +bool Camera2D::is_drag_horizontal_enabled() const { + return drag_horizontal_enabled; } -void Camera2D::set_v_drag_enabled(bool p_enabled) { - v_drag_enabled = p_enabled; +void Camera2D::set_drag_vertical_enabled(bool p_enabled) { + drag_vertical_enabled = p_enabled; } -bool Camera2D::is_v_drag_enabled() const { - return v_drag_enabled; +bool Camera2D::is_drag_vertical_enabled() const { + return drag_vertical_enabled; } -void Camera2D::set_v_offset(float p_offset) { - v_ofs = p_offset; - v_offset_changed = true; +void Camera2D::set_drag_vertical_offset(real_t p_offset) { + drag_vertical_offset = p_offset; + drag_vertical_offset_changed = true; Point2 old_smoothed_camera_pos = smoothed_camera_pos; _update_scroll(); smoothed_camera_pos = old_smoothed_camera_pos; } -float Camera2D::get_v_offset() const { - return v_ofs; +real_t Camera2D::get_drag_vertical_offset() const { + return drag_vertical_offset; } -void Camera2D::set_h_offset(float p_offset) { - h_ofs = p_offset; - h_offset_changed = true; +void Camera2D::set_drag_horizontal_offset(real_t p_offset) { + drag_horizontal_offset = p_offset; + drag_horizontal_offset_changed = true; Point2 old_smoothed_camera_pos = smoothed_camera_pos; _update_scroll(); smoothed_camera_pos = old_smoothed_camera_pos; } -float Camera2D::get_h_offset() const { - return h_ofs; +real_t Camera2D::get_drag_horizontal_offset() const { + return drag_horizontal_offset; } -void Camera2D::_set_old_smoothing(float p_enable) { +void Camera2D::_set_old_smoothing(real_t p_enable) { //compatibility if (p_enable > 0) { smoothing_enabled = true; @@ -568,6 +569,7 @@ void Camera2D::_set_old_smoothing(float p_enable) { void Camera2D::set_enable_follow_smoothing(bool p_enabled) { smoothing_enabled = p_enabled; + notify_property_list_changed(); } bool Camera2D::is_follow_smoothing_enabled() const { @@ -610,7 +612,9 @@ Node *Camera2D::get_custom_viewport() const { void Camera2D::set_screen_drawing_enabled(bool enable) { screen_drawing_enabled = enable; +#ifdef TOOLS_ENABLED update(); +#endif } bool Camera2D::is_screen_drawing_enabled() const { @@ -619,7 +623,9 @@ bool Camera2D::is_screen_drawing_enabled() const { void Camera2D::set_limit_drawing_enabled(bool enable) { limit_drawing_enabled = enable; +#ifdef TOOLS_ENABLED update(); +#endif } bool Camera2D::is_limit_drawing_enabled() const { @@ -628,13 +634,21 @@ bool Camera2D::is_limit_drawing_enabled() const { void Camera2D::set_margin_drawing_enabled(bool enable) { margin_drawing_enabled = enable; +#ifdef TOOLS_ENABLED update(); +#endif } bool Camera2D::is_margin_drawing_enabled() const { return margin_drawing_enabled; } +void Camera2D::_validate_property(PropertyInfo &property) const { + if (!smoothing_enabled && property.name == "smoothing_speed") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Camera2D::set_offset); ClassDB::bind_method(D_METHOD("get_offset"), &Camera2D::get_offset); @@ -651,8 +665,8 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_scroll"), &Camera2D::_update_scroll); - ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Camera2D::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &Camera2D::get_process_mode); + ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &Camera2D::set_process_callback); + ClassDB::bind_method(D_METHOD("get_process_callback"), &Camera2D::get_process_callback); ClassDB::bind_method(D_METHOD("_set_current", "current"), &Camera2D::_set_current); ClassDB::bind_method(D_METHOD("is_current"), &Camera2D::is_current); @@ -663,17 +677,17 @@ void Camera2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_limit_smoothing_enabled", "limit_smoothing_enabled"), &Camera2D::set_limit_smoothing_enabled); ClassDB::bind_method(D_METHOD("is_limit_smoothing_enabled"), &Camera2D::is_limit_smoothing_enabled); - ClassDB::bind_method(D_METHOD("set_v_drag_enabled", "enabled"), &Camera2D::set_v_drag_enabled); - ClassDB::bind_method(D_METHOD("is_v_drag_enabled"), &Camera2D::is_v_drag_enabled); + ClassDB::bind_method(D_METHOD("set_drag_vertical_enabled", "enabled"), &Camera2D::set_drag_vertical_enabled); + ClassDB::bind_method(D_METHOD("is_drag_vertical_enabled"), &Camera2D::is_drag_vertical_enabled); - ClassDB::bind_method(D_METHOD("set_h_drag_enabled", "enabled"), &Camera2D::set_h_drag_enabled); - ClassDB::bind_method(D_METHOD("is_h_drag_enabled"), &Camera2D::is_h_drag_enabled); + ClassDB::bind_method(D_METHOD("set_drag_horizontal_enabled", "enabled"), &Camera2D::set_drag_horizontal_enabled); + ClassDB::bind_method(D_METHOD("is_drag_horizontal_enabled"), &Camera2D::is_drag_horizontal_enabled); - ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera2D::set_v_offset); - ClassDB::bind_method(D_METHOD("get_v_offset"), &Camera2D::get_v_offset); + ClassDB::bind_method(D_METHOD("set_drag_vertical_offset", "offset"), &Camera2D::set_drag_vertical_offset); + ClassDB::bind_method(D_METHOD("get_drag_vertical_offset"), &Camera2D::get_drag_vertical_offset); - ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera2D::set_h_offset); - ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera2D::get_h_offset); + ClassDB::bind_method(D_METHOD("set_drag_horizontal_offset", "offset"), &Camera2D::set_drag_horizontal_offset); + ClassDB::bind_method(D_METHOD("get_drag_horizontal_offset"), &Camera2D::get_drag_horizontal_offset); ClassDB::bind_method(D_METHOD("set_drag_margin", "margin", "drag_margin"), &Camera2D::set_drag_margin); ClassDB::bind_method(D_METHOD("get_drag_margin", "margin"), &Camera2D::get_drag_margin); @@ -714,32 +728,28 @@ void Camera2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback"); ADD_GROUP("Limit", "limit_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_top"), "set_limit", "get_limit", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_right"), "set_limit", "get_limit", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom"), "set_limit", "get_limit", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_top"), "set_limit", "get_limit", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_right"), "set_limit", "get_limit", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_bottom"), "set_limit", "get_limit", SIDE_BOTTOM); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "limit_smoothed"), "set_limit_smoothing_enabled", "is_limit_smoothing_enabled"); - ADD_GROUP("Draw Margin", "draw_margin_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_margin_h_enabled"), "set_h_drag_enabled", "is_h_drag_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_margin_v_enabled"), "set_v_drag_enabled", "is_v_drag_enabled"); - ADD_GROUP("Smoothing", "smoothing_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "smoothing_speed"), "set_follow_smoothing", "get_follow_smoothing"); - ADD_GROUP("Offset", "offset_"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset_h", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_h_offset", "get_h_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "offset_v", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_v_offset", "get_v_offset"); - - ADD_GROUP("Drag Margin", "drag_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_margin_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_margin_top", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_margin_right", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_margin_bottom", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_BOTTOM); + ADD_GROUP("Drag", "drag_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_horizontal_enabled"), "set_drag_horizontal_enabled", "is_drag_horizontal_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_vertical_enabled"), "set_drag_vertical_enabled", "is_drag_vertical_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_horizontal_offset", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_drag_horizontal_offset", "get_drag_horizontal_offset"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_vertical_offset", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_drag_vertical_offset", "get_drag_vertical_offset"); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_left_margin", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_top_margin", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_right_margin", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "drag_bottom_margin", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", SIDE_BOTTOM); ADD_GROUP("Editor", "editor_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editor_draw_screen"), "set_screen_drawing_enabled", "is_screen_drawing_enabled"); @@ -753,39 +763,15 @@ void Camera2D::_bind_methods() { } Camera2D::Camera2D() { - anchor_mode = ANCHOR_MODE_DRAG_CENTER; - rotating = false; - current = false; - limit[MARGIN_LEFT] = -10000000; - limit[MARGIN_TOP] = -10000000; - limit[MARGIN_RIGHT] = 10000000; - limit[MARGIN_BOTTOM] = 10000000; - - drag_margin[MARGIN_LEFT] = 0.2; - drag_margin[MARGIN_TOP] = 0.2; - drag_margin[MARGIN_RIGHT] = 0.2; - drag_margin[MARGIN_BOTTOM] = 0.2; - camera_pos = Vector2(); - first = true; - smoothing_enabled = false; - limit_smoothing_enabled = false; - custom_viewport = nullptr; - - process_mode = CAMERA2D_PROCESS_IDLE; - - smoothing = 5.0; - zoom = Vector2(1, 1); - - screen_drawing_enabled = true; - limit_drawing_enabled = false; - margin_drawing_enabled = false; - - h_drag_enabled = false; - v_drag_enabled = false; - h_ofs = 0; - v_ofs = 0; - h_offset_changed = false; - v_offset_changed = false; + limit[SIDE_LEFT] = -10000000; + limit[SIDE_TOP] = -10000000; + limit[SIDE_RIGHT] = 10000000; + limit[SIDE_BOTTOM] = 10000000; + + drag_margin[SIDE_LEFT] = 0.2; + drag_margin[SIDE_TOP] = 0.2; + drag_margin[SIDE_RIGHT] = 0.2; + drag_margin[SIDE_BOTTOM] = 0.2; set_notify_transform(true); } diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 867a5562b2..7494e526cc 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,7 +43,7 @@ public: ANCHOR_MODE_DRAG_CENTER }; - enum Camera2DProcessMode { + enum Camera2DProcessCallback { CAMERA2D_PROCESS_PHYSICS, CAMERA2D_PROCESS_IDLE }; @@ -51,55 +51,56 @@ public: protected: Point2 camera_pos; Point2 smoothed_camera_pos; - bool first; + bool first = true; ObjectID custom_viewport_id; // to check validity - Viewport *custom_viewport; - Viewport *viewport; + Viewport *custom_viewport = nullptr; + Viewport *viewport = nullptr; StringName group_name; StringName canvas_group_name; RID canvas; Vector2 offset; - Vector2 zoom; - AnchorMode anchor_mode; - bool rotating; - bool current; - float smoothing; - bool smoothing_enabled; + Vector2 zoom = Vector2(1, 1); + AnchorMode anchor_mode = ANCHOR_MODE_DRAG_CENTER; + bool rotating = false; + bool current = false; + real_t smoothing = 5.0; + bool smoothing_enabled = false; int limit[4]; - bool limit_smoothing_enabled; - float drag_margin[4]; + bool limit_smoothing_enabled = false; - bool h_drag_enabled; - bool v_drag_enabled; - float h_ofs; - float v_ofs; - - bool h_offset_changed; - bool v_offset_changed; + real_t drag_margin[4]; + bool drag_horizontal_enabled = false; + bool drag_vertical_enabled = false; + real_t drag_horizontal_offset = 0.0; + real_t drag_vertical_offset = 0.0; + bool drag_horizontal_offset_changed = false; + bool drag_vertical_offset_changed = false; Point2 camera_screen_center; - void _update_process_mode(); + void _update_process_callback(); void _update_scroll(); void _make_current(Object *p_which); void _set_current(bool p_current); - void _set_old_smoothing(float p_enable); + void _set_old_smoothing(real_t p_enable); - bool screen_drawing_enabled; - bool limit_drawing_enabled; - bool margin_drawing_enabled; + bool screen_drawing_enabled = true; + bool limit_drawing_enabled = false; + bool margin_drawing_enabled = false; - Camera2DProcessMode process_mode; + Camera2DProcessCallback process_callback = CAMERA2D_PROCESS_IDLE; Size2 _get_camera_screen_size() const; protected: virtual Transform2D get_camera_transform(); + void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: void set_offset(const Vector2 &p_offset); @@ -111,35 +112,35 @@ public: void set_rotating(bool p_rotating); bool is_rotating() const; - void set_limit(Margin p_margin, int p_limit); - int get_limit(Margin p_margin) const; + void set_limit(Side p_side, int p_limit); + int get_limit(Side p_side) const; void set_limit_smoothing_enabled(bool enable); bool is_limit_smoothing_enabled() const; - void set_h_drag_enabled(bool p_enabled); - bool is_h_drag_enabled() const; + void set_drag_horizontal_enabled(bool p_enabled); + bool is_drag_horizontal_enabled() const; - void set_v_drag_enabled(bool p_enabled); - bool is_v_drag_enabled() const; + void set_drag_vertical_enabled(bool p_enabled); + bool is_drag_vertical_enabled() const; - void set_drag_margin(Margin p_margin, float p_drag_margin); - float get_drag_margin(Margin p_margin) const; + void set_drag_margin(Side p_side, real_t p_drag_margin); + real_t get_drag_margin(Side p_side) const; - void set_v_offset(float p_offset); - float get_v_offset() const; + void set_drag_horizontal_offset(real_t p_offset); + real_t get_drag_horizontal_offset() const; - void set_h_offset(float p_offset); - float get_h_offset() const; + void set_drag_vertical_offset(real_t p_offset); + real_t get_drag_vertical_offset() const; void set_enable_follow_smoothing(bool p_enabled); bool is_follow_smoothing_enabled() const; - void set_follow_smoothing(float p_speed); - float get_follow_smoothing() const; + void set_follow_smoothing(real_t p_speed); + real_t get_follow_smoothing() const; - void set_process_mode(Camera2DProcessMode p_mode); - Camera2DProcessMode get_process_mode() const; + void set_process_callback(Camera2DProcessCallback p_mode); + Camera2DProcessCallback get_process_callback() const; void make_current(); void clear_current(); @@ -171,6 +172,6 @@ public: }; VARIANT_ENUM_CAST(Camera2D::AnchorMode); -VARIANT_ENUM_CAST(Camera2D::Camera2DProcessMode); +VARIANT_ENUM_CAST(Camera2D::Camera2DProcessCallback); #endif // CAMERA_2D_H diff --git a/scene/2d/canvas_group.cpp b/scene/2d/canvas_group.cpp index 39cae8e0c6..ee025b6dfc 100644 --- a/scene/2d/canvas_group.cpp +++ b/scene/2d/canvas_group.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -30,7 +30,7 @@ #include "canvas_group.h" -void CanvasGroup::set_fit_margin(float p_fit_margin) { +void CanvasGroup::set_fit_margin(real_t p_fit_margin) { ERR_FAIL_COND(p_fit_margin < 0.0); fit_margin = p_fit_margin; @@ -39,11 +39,11 @@ void CanvasGroup::set_fit_margin(float p_fit_margin) { update(); } -float CanvasGroup::get_fit_margin() const { +real_t CanvasGroup::get_fit_margin() const { return fit_margin; } -void CanvasGroup::set_clear_margin(float p_clear_margin) { +void CanvasGroup::set_clear_margin(real_t p_clear_margin) { ERR_FAIL_COND(p_clear_margin < 0.0); clear_margin = p_clear_margin; @@ -52,7 +52,7 @@ void CanvasGroup::set_clear_margin(float p_clear_margin) { update(); } -float CanvasGroup::get_clear_margin() const { +real_t CanvasGroup::get_clear_margin() const { return clear_margin; } @@ -84,4 +84,5 @@ CanvasGroup::CanvasGroup() { set_fit_margin(10.0); //sets things } CanvasGroup::~CanvasGroup() { + RS::get_singleton()->canvas_item_set_canvas_group_mode(get_canvas_item(), RS::CANVAS_GROUP_MODE_DISABLED); } diff --git a/scene/2d/canvas_group.h b/scene/2d/canvas_group.h index 19630befc7..b487d7a098 100644 --- a/scene/2d/canvas_group.h +++ b/scene/2d/canvas_group.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,19 +35,19 @@ class CanvasGroup : public Node2D { GDCLASS(CanvasGroup, Node2D) - float fit_margin = 10.0; - float clear_margin = 10.0; + real_t fit_margin = 10.0; + real_t 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_fit_margin(real_t p_fit_margin); + real_t get_fit_margin() const; - void set_clear_margin(float p_clear_margin); - float get_clear_margin() const; + void set_clear_margin(real_t p_clear_margin); + real_t get_clear_margin() const; void set_use_mipmaps(bool p_use_mipmaps); bool is_using_mipmaps() const; diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp index 8fb16534e8..5d5aaae505 100644 --- a/scene/2d/canvas_modulate.cpp +++ b/scene/2d/canvas_modulate.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -84,7 +84,7 @@ String CanvasModulate::get_configuration_warning() const { get_tree()->get_nodes_in_group("_canvas_modulate_" + itos(get_canvas().get_id()), &nodes); if (nodes.size() > 1) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -94,7 +94,6 @@ String CanvasModulate::get_configuration_warning() const { } CanvasModulate::CanvasModulate() { - color = Color(1, 1, 1, 1); } CanvasModulate::~CanvasModulate() { diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h index eac3cf9e54..4d55a5d9cb 100644 --- a/scene/2d/canvas_modulate.h +++ b/scene/2d/canvas_modulate.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class CanvasModulate : public Node2D { GDCLASS(CanvasModulate, Node2D); - Color color; + Color color = Color(1, 1, 1, 1); protected: void _notification(int p_what); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index fe16d4089a..c83ed36917 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -165,7 +165,7 @@ bool CollisionObject2D::is_shape_owner_one_way_collision_enabled(uint32_t p_owne return shapes[p_owner].one_way_collision; } -void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owner, float p_margin) { +void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owner, real_t p_margin) { if (area) { return; //not for areas } @@ -179,7 +179,7 @@ void CollisionObject2D::shape_owner_set_one_way_collision_margin(uint32_t p_owne } } -float CollisionObject2D::get_shape_owner_one_way_collision_margin(uint32_t p_owner) const { +real_t CollisionObject2D::get_shape_owner_one_way_collision_margin(uint32_t p_owner) const { ERR_FAIL_COND_V(!shapes.has(p_owner), 0); return shapes[p_owner].one_way_collision_margin; @@ -366,8 +366,8 @@ void CollisionObject2D::_update_pickable() { String CollisionObject2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); - if (shapes.empty()) { - if (!warning.empty()) { + if (shapes.is_empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape."); diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h index 8eff1b3aec..e82b61d441 100644 --- a/scene/2d/collision_object_2d.h +++ b/scene/2d/collision_object_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,35 +37,29 @@ class CollisionObject2D : public Node2D { GDCLASS(CollisionObject2D, Node2D); - bool area; + bool area = false; RID rid; - bool pickable; + bool pickable = false; struct ShapeData { - Object *owner; + Object *owner = nullptr; Transform2D xform; struct Shape { Ref<Shape2D> shape; - int index; + int index = 0; }; Vector<Shape> shapes; - bool disabled; - bool one_way_collision; - float one_way_collision_margin; - - ShapeData() { - disabled = false; - one_way_collision = false; - one_way_collision_margin = 0; - owner = nullptr; - } + + bool disabled = false; + bool one_way_collision = false; + real_t one_way_collision_margin = 0.0; }; - int total_subshapes; + int total_subshapes = 0; Map<uint32_t, ShapeData> shapes; - bool only_update_transform_changes; //this is used for sync physics in KinematicBody + bool only_update_transform_changes = false; //this is used for sync physics in KinematicBody protected: CollisionObject2D(RID p_rid, bool p_area); @@ -97,8 +91,8 @@ public: void shape_owner_set_one_way_collision(uint32_t p_owner, bool p_enable); bool is_shape_owner_one_way_collision_enabled(uint32_t p_owner) const; - void shape_owner_set_one_way_collision_margin(uint32_t p_owner, float p_margin); - float get_shape_owner_one_way_collision_margin(uint32_t p_owner) const; + void shape_owner_set_one_way_collision_margin(uint32_t p_owner, real_t p_margin); + real_t get_shape_owner_one_way_collision_margin(uint32_t p_owner) const; void shape_owner_add_shape(uint32_t p_owner, const Ref<Shape2D> &p_shape); int shape_owner_get_shape_count(uint32_t p_owner) const; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 64d82d715c..38198c496e 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,18 +36,18 @@ #include "scene/resources/concave_polygon_shape_2d.h" #include "scene/resources/convex_polygon_shape_2d.h" -#include "thirdparty/misc/triangulator.h" +#include "thirdparty/misc/polypartition.h" void CollisionPolygon2D::_build_polygon() { parent->shape_owner_clear_shapes(owner_id); - if (polygon.size() == 0) { - return; - } - bool solids = build_mode == BUILD_SOLIDS; if (solids) { + if (polygon.size() < 3) { + return; + } + //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them Vector<Vector<Vector2>> decomp = _decompose_in_convex(); @@ -58,6 +58,10 @@ void CollisionPolygon2D::_build_polygon() { } } else { + if (polygon.size() < 2) { + return; + } + Ref<ConcavePolygonShape2D> concave = memnew(ConcavePolygonShape2D); Vector<Vector2> segments; @@ -132,25 +136,28 @@ void CollisionPolygon2D::_notification(int p_what) { break; } - for (int i = 0; i < polygon.size(); i++) { + int polygon_count = polygon.size(); + for (int i = 0; i < polygon_count; i++) { Vector2 p = polygon[i]; - Vector2 n = polygon[(i + 1) % polygon.size()]; + Vector2 n = polygon[(i + 1) % polygon_count]; // draw line with width <= 1, so it does not scale with zoom and break pixel exact editing draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 1); } + + if (polygon_count > 2) { #define DEBUG_DECOMPOSE #if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE) + Vector<Vector<Vector2>> decomp = _decompose_in_convex(); - Vector<Vector<Vector2>> decomp = _decompose_in_convex(); - - Color c(0.4, 0.9, 0.1); - for (int i = 0; i < decomp.size(); i++) { - c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5); - draw_colored_polygon(decomp[i], c); - } + Color c(0.4, 0.9, 0.1); + for (int i = 0; i < decomp.size(); i++) { + c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5); + draw_colored_polygon(decomp[i], c); + } #else - draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); + draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); #endif + } if (one_way_collision) { Color dcol = get_tree()->get_debug_collisions_color(); //0.9,0.2,0.2,0.4); @@ -158,7 +165,7 @@ void CollisionPolygon2D::_notification(int p_what) { Vector2 line_to(0, 20); draw_line(Vector2(), line_to, dcol, 3); Vector<Vector2> pts; - float tsize = 8; + real_t tsize = 8; pts.push_back(line_to + (Vector2(0, tsize))); pts.push_back(line_to + (Vector2(Math_SQRT12 * tsize, 0))); pts.push_back(line_to + (Vector2(-Math_SQRT12 * tsize, 0))); @@ -194,6 +201,7 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2> &p_polygon) { if (parent) { _build_polygon(); + _update_in_shape_owner(); } update(); update_configuration_warning(); @@ -208,7 +216,10 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { build_mode = p_mode; if (parent) { _build_polygon(); + _update_in_shape_owner(); } + update(); + update_configuration_warning(); } CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { @@ -233,17 +244,33 @@ String CollisionPolygon2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!Object::cast_to<CollisionObject2D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_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()) { - if (!warning.empty()) { + int polygon_count = polygon.size(); + if (polygon_count == 0) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("An empty CollisionPolygon2D has no effect on collision."); + } else { + bool solids = build_mode == BUILD_SOLIDS; + if (solids) { + if (polygon_count < 3) { + if (!warning.is_empty()) { + warning += "\n\n"; + } + warning += TTR("Invalid polygon. At least 3 points are needed in 'Solids' build mode."); + } + } else if (polygon_count < 2) { + if (!warning.is_empty()) { + warning += "\n\n"; + } + warning += TTR("Invalid polygon. At least 2 points are needed in 'Segments' build mode."); + } } return warning; @@ -273,14 +300,14 @@ bool CollisionPolygon2D::is_one_way_collision_enabled() const { return one_way_collision; } -void CollisionPolygon2D::set_one_way_collision_margin(float p_margin) { +void CollisionPolygon2D::set_one_way_collision_margin(real_t p_margin) { one_way_collision_margin = p_margin; if (parent) { parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); } } -float CollisionPolygon2D::get_one_way_collision_margin() const { +real_t CollisionPolygon2D::get_one_way_collision_margin() const { return one_way_collision_margin; } @@ -308,12 +335,5 @@ void CollisionPolygon2D::_bind_methods() { } CollisionPolygon2D::CollisionPolygon2D() { - aabb = Rect2(-10, -10, 20, 20); - build_mode = BUILD_SOLIDS; set_notify_local_transform(true); - parent = nullptr; - owner_id = 0; - disabled = false; - one_way_collision = false; - one_way_collision_margin = 1.0; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 0f6b654149..9df9802629 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,14 +46,14 @@ public: }; protected: - Rect2 aabb; - BuildMode build_mode; + Rect2 aabb = Rect2(-10, -10, 20, 20); + BuildMode build_mode = BUILD_SOLIDS; Vector<Point2> polygon; - uint32_t owner_id; - CollisionObject2D *parent; - bool disabled; - bool one_way_collision; - float one_way_collision_margin; + uint32_t owner_id = 0; + CollisionObject2D *parent = nullptr; + bool disabled = false; + bool one_way_collision = false; + real_t one_way_collision_margin = 1.0; Vector<Vector<Vector2>> _decompose_in_convex(); @@ -86,8 +86,8 @@ public: void set_one_way_collision(bool p_enable); bool is_one_way_collision_enabled() const; - void set_one_way_collision_margin(float p_margin); - float get_one_way_collision_margin() const; + void set_one_way_collision_margin(real_t p_margin); + real_t get_one_way_collision_margin() const; CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index a5cd624235..93949f741b 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -110,6 +110,7 @@ void CollisionShape2D::_notification(int p_what) { draw_col.r = g; draw_col.g = g; draw_col.b = g; + draw_col.a *= 0.5; } shape->draw(get_canvas_item(), draw_col); @@ -125,7 +126,7 @@ void CollisionShape2D::_notification(int p_what) { Vector2 line_to(0, 20); draw_line(Vector2(), line_to, draw_col, 2); Vector<Vector2> pts; - float tsize = 8; + real_t tsize = 8; pts.push_back(line_to + (Vector2(0, tsize))); pts.push_back(line_to + (Vector2(Math_SQRT12 * tsize, 0))); pts.push_back(line_to + (Vector2(-Math_SQRT12 * tsize, 0))); @@ -141,6 +142,9 @@ void CollisionShape2D::_notification(int p_what) { } void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) { + if (p_shape == shape) { + return; + } if (shape.is_valid()) { shape->disconnect("changed", callable_mp(this, &CollisionShape2D::_shape_changed)); } @@ -151,6 +155,7 @@ void CollisionShape2D::set_shape(const Ref<Shape2D> &p_shape) { if (shape.is_valid()) { parent->shape_owner_add_shape(owner_id, shape); } + _update_in_shape_owner(); } if (shape.is_valid()) { @@ -211,14 +216,14 @@ bool CollisionShape2D::is_one_way_collision_enabled() const { return one_way_collision; } -void CollisionShape2D::set_one_way_collision_margin(float p_margin) { +void CollisionShape2D::set_one_way_collision_margin(real_t p_margin) { one_way_collision_margin = p_margin; if (parent) { parent->shape_owner_set_one_way_collision_margin(owner_id, one_way_collision_margin); } } -float CollisionShape2D::get_one_way_collision_margin() const { +real_t CollisionShape2D::get_one_way_collision_margin() const { return one_way_collision_margin; } @@ -239,11 +244,5 @@ void CollisionShape2D::_bind_methods() { } CollisionShape2D::CollisionShape2D() { - rect = Rect2(-Point2(10, 10), Point2(20, 20)); set_notify_local_transform(true); - owner_id = 0; - parent = nullptr; - disabled = false; - one_way_collision = false; - one_way_collision_margin = 1.0; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index ced90d46f0..695d0c6657 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,13 +39,13 @@ class CollisionObject2D; class CollisionShape2D : public Node2D { GDCLASS(CollisionShape2D, Node2D); Ref<Shape2D> shape; - Rect2 rect; - uint32_t owner_id; - CollisionObject2D *parent; + Rect2 rect = Rect2(-Point2(10, 10), Point2(20, 20)); + uint32_t owner_id = 0; + CollisionObject2D *parent = nullptr; void _shape_changed(); - bool disabled; - bool one_way_collision; - float one_way_collision_margin; + bool disabled = false; + bool one_way_collision = false; + real_t one_way_collision_margin = 1.0; void _update_in_shape_owner(bool p_xform_only = false); @@ -69,8 +69,8 @@ public: void set_one_way_collision(bool p_enable); bool is_one_way_collision_enabled() const; - void set_one_way_collision_margin(float p_margin); - float get_one_way_collision_margin() const; + void set_one_way_collision_margin(real_t p_margin); + real_t get_one_way_collision_margin() const; virtual String get_configuration_warning() const override; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 3649746c40..6a69a4c618 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -60,7 +60,7 @@ void CPUParticles2D::set_amount(int p_amount) { } particle_data.resize((8 + 4 + 4) * p_amount); - RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true); + RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_2D, true, true); particle_order.resize(p_amount); } @@ -78,11 +78,11 @@ void CPUParticles2D::set_pre_process_time(float p_time) { pre_process_time = p_time; } -void CPUParticles2D::set_explosiveness_ratio(float p_ratio) { +void CPUParticles2D::set_explosiveness_ratio(real_t p_ratio) { explosiveness_ratio = p_ratio; } -void CPUParticles2D::set_randomness_ratio(float p_ratio) { +void CPUParticles2D::set_randomness_ratio(real_t p_ratio) { randomness_ratio = p_ratio; } @@ -95,7 +95,7 @@ void CPUParticles2D::set_use_local_coordinates(bool p_enable) { set_notify_transform(!p_enable); } -void CPUParticles2D::set_speed_scale(float p_scale) { +void CPUParticles2D::set_speed_scale(real_t p_scale) { speed_scale = p_scale; } @@ -119,11 +119,11 @@ float CPUParticles2D::get_pre_process_time() const { return pre_process_time; } -float CPUParticles2D::get_explosiveness_ratio() const { +real_t CPUParticles2D::get_explosiveness_ratio() const { return explosiveness_ratio; } -float CPUParticles2D::get_randomness_ratio() const { +real_t CPUParticles2D::get_randomness_ratio() const { return randomness_ratio; } @@ -135,7 +135,7 @@ bool CPUParticles2D::get_use_local_coordinates() const { return local_coords; } -float CPUParticles2D::get_speed_scale() const { +real_t CPUParticles2D::get_speed_scale() const { return speed_scale; } @@ -289,39 +289,39 @@ Vector2 CPUParticles2D::get_direction() const { return direction; } -void CPUParticles2D::set_spread(float p_spread) { +void CPUParticles2D::set_spread(real_t p_spread) { spread = p_spread; } -float CPUParticles2D::get_spread() const { +real_t CPUParticles2D::get_spread() const { return spread; } -void CPUParticles2D::set_param(Parameter p_param, float p_value) { +void CPUParticles2D::set_param(Parameter p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); parameters[p_param] = p_value; } -float CPUParticles2D::get_param(Parameter p_param) const { +real_t CPUParticles2D::get_param(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return parameters[p_param]; } -void CPUParticles2D::set_param_randomness(Parameter p_param, float p_value) { +void CPUParticles2D::set_param_randomness(Parameter p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); randomness[p_param] = p_value; } -float CPUParticles2D::get_param_randomness(Parameter p_param) const { +real_t CPUParticles2D::get_param_randomness(Parameter p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return randomness[p_param]; } -static void _adjust_curve_range(const Ref<Curve> &p_curve, float p_min, float p_max) { +static void _adjust_curve_range(const Ref<Curve> &p_curve, real_t p_min, real_t p_max) { Ref<Curve> curve = p_curve; if (!curve.is_valid()) { return; @@ -410,10 +410,10 @@ bool CPUParticles2D::get_particle_flag(ParticleFlags p_particle_flag) const { void CPUParticles2D::set_emission_shape(EmissionShape p_shape) { ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; - _change_notify(); + notify_property_list_changed(); } -void CPUParticles2D::set_emission_sphere_radius(float p_radius) { +void CPUParticles2D::set_emission_sphere_radius(real_t p_radius) { emission_sphere_radius = p_radius; } @@ -433,7 +433,7 @@ void CPUParticles2D::set_emission_colors(const Vector<Color> &p_colors) { emission_colors = p_colors; } -float CPUParticles2D::get_emission_sphere_radius() const { +real_t CPUParticles2D::get_emission_sphere_radius() const { return emission_sphere_radius; } @@ -502,7 +502,7 @@ static uint32_t idhash(uint32_t x) { return x; } -static float rand_from_seed(uint32_t &seed) { +static real_t rand_from_seed(uint32_t &seed) { int k; int s = int(seed); if (s == 0) { @@ -514,7 +514,7 @@ static float rand_from_seed(uint32_t &seed) { s += 2147483647; } seed = uint32_t(s); - return float(seed % uint32_t(65536)) / 65535.0; + return (seed % uint32_t(65536)) / 65535.0; } void CPUParticles2D::_update_internal() { @@ -599,7 +599,7 @@ void CPUParticles2D::_particles_process(float p_delta) { cycle++; if (one_shot && cycle > 0) { set_emitting(false); - _change_notify(); + notify_property_list_changed(); } } @@ -625,7 +625,7 @@ void CPUParticles2D::_particles_process(float p_delta) { // The phase is a ratio between 0 (birth) and 1 (end of life) for each particle. // While we use time in tests later on, for randomness we use the phase as done in the // original shader code, and we later multiply by lifetime to get the time. - float restart_phase = float(i) / float(pcount); + real_t restart_phase = real_t(i) / real_t(pcount); if (randomness_ratio > 0.0) { uint32_t seed = cycle; @@ -634,8 +634,8 @@ void CPUParticles2D::_particles_process(float p_delta) { } seed *= uint32_t(pcount); seed += uint32_t(i); - float random = float(idhash(seed) % uint32_t(65536)) / 65536.0; - restart_phase += randomness_ratio * random * 1.0 / float(pcount); + real_t random = (idhash(seed) % uint32_t(65536)) / 65536.0; + restart_phase += randomness_ratio * random * 1.0 / pcount; } restart_phase *= (1.0 - explosiveness_ratio); @@ -671,6 +671,8 @@ void CPUParticles2D::_particles_process(float p_delta) { restart = true; } + float tv = 0.0; + if (restart) { if (!emitting) { p.active = false; @@ -678,19 +680,19 @@ void CPUParticles2D::_particles_process(float p_delta) { } p.active = true; - /*float tex_linear_velocity = 0; + /*real_t tex_linear_velocity = 0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(0); }*/ - float tex_angle = 0.0; + real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0); + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } - float tex_anim_offset = 0.0; + real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0); + tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv); } p.seed = Math::rand(); @@ -700,16 +702,16 @@ void CPUParticles2D::_particles_process(float p_delta) { p.hue_rot_rand = Math::randf(); p.anim_offset_rand = Math::randf(); - float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + real_t angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); Vector2 rot = Vector2(Math::cos(angle1_rad), Math::sin(angle1_rad)); - p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); + p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp((real_t)1.0, real_t(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); - float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); + real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]); p.rotation = Math::deg2rad(base_angle); p.custom[0] = 0.0; // unused p.custom[1] = 0.0; // phase [0..1] - p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1] + p.custom[2] = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]); //animation phase [0..1] p.custom[3] = 0.0; p.transform = Transform2D(); p.time = 0; @@ -721,8 +723,8 @@ void CPUParticles2D::_particles_process(float p_delta) { //do none } break; case EMISSION_SHAPE_SPHERE: { - float s = Math::randf(), t = 2.0 * Math_PI * Math::randf(); - float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); + real_t s = Math::randf(), t = Math_TAU * Math::randf(); + real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform[2] = Vector2(Math::cos(t), Math::sin(t)) * radius; } break; case EMISSION_SHAPE_RECTANGLE: { @@ -743,7 +745,7 @@ void CPUParticles2D::_particles_process(float p_delta) { Vector2 normal = emission_normals.get(random_idx); Transform2D m2; m2.set_axis(0, normal); - m2.set_axis(1, normal.tangent()); + m2.set_axis(1, normal.orthogonal()); p.velocity = m2.basis_xform(p.velocity); } @@ -765,79 +767,81 @@ void CPUParticles2D::_particles_process(float p_delta) { continue; } else if (p.time > p.lifetime) { p.active = false; + tv = 1.0; } else { uint32_t alt_seed = p.seed; p.time += local_delta; p.custom[1] = p.time / lifetime; + tv = p.time / p.lifetime; - float tex_linear_velocity = 0.0; + real_t tex_linear_velocity = 0.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv); } - float tex_orbit_velocity = 0.0; + real_t tex_orbit_velocity = 0.0; if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv); } - float tex_angular_velocity = 0.0; + real_t tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); + tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv); } - float tex_linear_accel = 0.0; + real_t tex_linear_accel = 0.0; if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]); + tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv); } - float tex_tangential_accel = 0.0; + real_t tex_tangential_accel = 0.0; if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]); + tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv); } - float tex_radial_accel = 0.0; + real_t tex_radial_accel = 0.0; if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]); + tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv); } - float tex_damping = 0.0; + real_t tex_damping = 0.0; if (curve_parameters[PARAM_DAMPING].is_valid()) { - tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]); + tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv); } - float tex_angle = 0.0; + real_t tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]); + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } - float tex_anim_speed = 0.0; + real_t tex_anim_speed = 0.0; if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { - tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]); + tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv); } - float tex_anim_offset = 0.0; + real_t tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]); + tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv); } Vector2 force = gravity; Vector2 pos = p.transform[2]; //apply linear acceleration - force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2(); + force += p.velocity.length() > 0.0 ? p.velocity.normalized() * (parameters[PARAM_LINEAR_ACCEL] + tex_linear_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_LINEAR_ACCEL]) : Vector2(); //apply radial acceleration Vector2 org = emission_xform[2]; Vector2 diff = pos - org; - force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2(); + force += diff.length() > 0.0 ? diff.normalized() * (parameters[PARAM_RADIAL_ACCEL] + tex_radial_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_RADIAL_ACCEL]) : Vector2(); //apply tangential acceleration; Vector2 yx = Vector2(diff.y, diff.x); - force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); + force += yx.length() > 0.0 ? (yx * Vector2(-1.0, 1.0)).normalized() * ((parameters[PARAM_TANGENTIAL_ACCEL] + tex_tangential_accel) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_TANGENTIAL_ACCEL])) : Vector2(); //apply attractor forces p.velocity += force * local_delta; //orbit velocity - float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); + real_t orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); if (orbit_amount != 0.0) { - float ang = orbit_amount * local_delta * Math_PI * 2.0; + real_t ang = orbit_amount * local_delta * Math_TAU; // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); @@ -849,8 +853,8 @@ void CPUParticles2D::_particles_process(float p_delta) { } if (parameters[PARAM_DAMPING] + tex_damping > 0.0) { - float v = p.velocity.length(); - float damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]); + real_t v = p.velocity.length(); + real_t damp = (parameters[PARAM_DAMPING] + tex_damping) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_DAMPING]); v -= damp * local_delta; if (v < 0.0) { p.velocity = Vector2(); @@ -858,28 +862,28 @@ void CPUParticles2D::_particles_process(float p_delta) { p.velocity = p.velocity.normalized() * v; } } - float base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp(1.0f, p.angle_rand, randomness[PARAM_ANGLE]); - base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]); + real_t base_angle = (parameters[PARAM_ANGLE] + tex_angle) * Math::lerp((real_t)1.0, p.angle_rand, randomness[PARAM_ANGLE]); + base_angle += p.custom[1] * lifetime * (parameters[PARAM_ANGULAR_VELOCITY] + tex_angular_velocity) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed) * 2.0f - 1.0f, randomness[PARAM_ANGULAR_VELOCITY]); p.rotation = Math::deg2rad(base_angle); //angle - float animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp(1.0f, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); + real_t animation_phase = (parameters[PARAM_ANIM_OFFSET] + tex_anim_offset) * Math::lerp((real_t)1.0, p.anim_offset_rand, randomness[PARAM_ANIM_OFFSET]) + p.custom[1] * (parameters[PARAM_ANIM_SPEED] + tex_anim_speed) * Math::lerp((real_t)1.0, rand_from_seed(alt_seed), randomness[PARAM_ANIM_SPEED]); p.custom[2] = animation_phase; } //apply color //apply hue rotation - float tex_scale = 1.0; + real_t tex_scale = 1.0; if (curve_parameters[PARAM_SCALE].is_valid()) { - tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]); + tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv); } - float tex_hue_variation = 0.0; + real_t tex_hue_variation = 0.0; if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { - tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]); + tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); } - float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); - float hue_rot_c = Math::cos(hue_rot_angle); - float hue_rot_s = Math::sin(hue_rot_angle); + real_t hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); + real_t hue_rot_c = Math::cos(hue_rot_angle); + real_t hue_rot_s = Math::sin(hue_rot_angle); Basis hue_rot_mat; { @@ -893,7 +897,7 @@ void CPUParticles2D::_particles_process(float p_delta) { } if (color_ramp.is_valid()) { - p.color = color_ramp->get_color_at_offset(p.custom[1]) * color; + p.color = color_ramp->get_color_at_offset(tv) * color; } else { p.color = color; } @@ -908,7 +912,7 @@ void CPUParticles2D::_particles_process(float p_delta) { if (particle_flags[PARTICLE_FLAG_ALIGN_Y_TO_VELOCITY]) { if (p.velocity.length() > 0.0) { p.transform.elements[1] = p.velocity.normalized(); - p.transform.elements[0] = p.transform.elements[1].tangent(); + p.transform.elements[0] = p.transform.elements[1].orthogonal(); } } else { @@ -917,7 +921,7 @@ void CPUParticles2D::_particles_process(float p_delta) { } //scale by scale - float base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], 1.0f, p.scale_rand * randomness[PARAM_SCALE]); + real_t base_scale = tex_scale * Math::lerp(parameters[PARAM_SCALE], (real_t)1.0, p.scale_rand * randomness[PARAM_SCALE]); if (base_scale < 0.000001) { base_scale = 0.000001; } @@ -1028,66 +1032,64 @@ void CPUParticles2D::_update_render_thread() { } void CPUParticles2D::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - set_process_internal(emitting); - } - - if (p_what == NOTIFICATION_EXIT_TREE) { - _set_redraw(false); - } - - if (p_what == NOTIFICATION_DRAW) { - // first update before rendering to avoid one frame delay after emitting starts - if (emitting && (time == 0)) { - _update_internal(); - } - - if (!redraw) { - return; // don't add to render list - } - - RID texrid; - if (texture.is_valid()) { - texrid = texture->get_rid(); - } - - RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); - } - - if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - _update_internal(); - } - - if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { - inv_emission_transform = get_global_transform().affine_inverse(); + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + set_process_internal(emitting); + } break; + case NOTIFICATION_EXIT_TREE: { + _set_redraw(false); + } break; + case NOTIFICATION_DRAW: { + // first update before rendering to avoid one frame delay after emitting starts + if (emitting && (time == 0)) { + _update_internal(); + } - if (!local_coords) { - int pc = particles.size(); + if (!redraw) { + return; // don't add to render list + } - float *w = particle_data.ptrw(); - const Particle *r = particles.ptr(); - float *ptr = w; + RID texrid; + if (texture.is_valid()) { + texrid = texture->get_rid(); + } - for (int i = 0; i < pc; i++) { - Transform2D t = inv_emission_transform * r[i].transform; + RS::get_singleton()->canvas_item_add_multimesh(get_canvas_item(), multimesh, texrid); + } break; + case NOTIFICATION_INTERNAL_PROCESS: { + _update_internal(); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + inv_emission_transform = get_global_transform().affine_inverse(); - if (r[i].active) { - ptr[0] = t.elements[0][0]; - ptr[1] = t.elements[1][0]; - ptr[2] = 0; - ptr[3] = t.elements[2][0]; - ptr[4] = t.elements[0][1]; - ptr[5] = t.elements[1][1]; - ptr[6] = 0; - ptr[7] = t.elements[2][1]; + if (!local_coords) { + int pc = particles.size(); + + float *w = particle_data.ptrw(); + const Particle *r = particles.ptr(); + float *ptr = w; + + for (int i = 0; i < pc; i++) { + Transform2D t = inv_emission_transform * r[i].transform; + + if (r[i].active) { + ptr[0] = t.elements[0][0]; + ptr[1] = t.elements[1][0]; + ptr[2] = 0; + ptr[3] = t.elements[2][0]; + ptr[4] = t.elements[0][1]; + ptr[5] = t.elements[1][1]; + ptr[6] = 0; + ptr[7] = t.elements[2][1]; + + } else { + zeromem(ptr, sizeof(float) * 8); + } - } else { - zeromem(ptr, sizeof(float) * 8); + ptr += 16; } - - ptr += 16; } - } + } break; } } @@ -1365,34 +1367,14 @@ void CPUParticles2D::_bind_methods() { } CPUParticles2D::CPUParticles2D() { - time = 0; - inactive_time = 0; - frame_remainder = 0; - cycle = 0; - redraw = false; - emitting = false; - mesh = RenderingServer::get_singleton()->mesh_create(); multimesh = RenderingServer::get_singleton()->multimesh_create(); RenderingServer::get_singleton()->multimesh_set_mesh(multimesh, mesh); set_emitting(true); - set_one_shot(false); set_amount(8); - set_lifetime(1); - set_fixed_fps(0); - set_fractional_delta(true); - set_pre_process_time(0); - set_explosiveness_ratio(0); - set_randomness_ratio(0); - set_lifetime_randomness(0); set_use_local_coordinates(true); - set_draw_order(DRAW_ORDER_INDEX); - set_speed_scale(1); - - set_direction(Vector2(1, 0)); - set_spread(45); set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_ORBIT_VELOCITY, 0); @@ -1405,11 +1387,6 @@ CPUParticles2D::CPUParticles2D() { set_param(PARAM_HUE_VARIATION, 0); set_param(PARAM_ANIM_SPEED, 0); set_param(PARAM_ANIM_OFFSET, 0); - set_emission_shape(EMISSION_SHAPE_POINT); - set_emission_sphere_radius(1); - set_emission_rect_extents(Vector2(1, 1)); - - set_gravity(Vector2(0, 98)); for (int i = 0; i < PARAM_MAX; i++) { set_param_randomness(Parameter(i), 0); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index 857f19b20f..ab04ee4a57 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -78,31 +78,31 @@ public: }; private: - bool emitting; + bool emitting = false; struct Particle { Transform2D transform; Color color; - float custom[4]; - float rotation; + float custom[4] = {}; + real_t rotation = 0.0; Vector2 velocity; - bool active; - float angle_rand; - float scale_rand; - float hue_rot_rand; - float anim_offset_rand; - float time; - float lifetime; + bool active = false; + real_t angle_rand = 0.0; + real_t scale_rand = 0.0; + real_t hue_rot_rand = 0.0; + real_t anim_offset_rand = 0.0; + float time = 0.0; + float lifetime = 0.0; Color base_color; - uint32_t seed; + uint32_t seed = 0; }; - float time; - float inactive_time; - float frame_remainder; - int cycle; - bool redraw; + float time = 0.0; + float inactive_time = 0.0; + float frame_remainder = 0.0; + int cycle = 0; + bool redraw = false; RID mesh; RID multimesh; @@ -112,7 +112,7 @@ private: Vector<int> particle_order; struct SortLifetime { - const Particle *particles; + const Particle *particles = nullptr; bool operator()(int p_a, int p_b) const { return particles[p_a].time > particles[p_b].time; @@ -120,7 +120,7 @@ private: }; struct SortAxis { - const Particle *particles; + const Particle *particles = nullptr; Vector2 axis; bool operator()(int p_a, int p_b) const { return axis.dot(particles[p_a].transform[2]) < axis.dot(particles[p_b].transform[2]); @@ -129,31 +129,31 @@ private: // - bool one_shot; + bool one_shot = false; - float lifetime; - float pre_process_time; - float explosiveness_ratio; - float randomness_ratio; - float lifetime_randomness; - float speed_scale; + float lifetime = 1.0; + float pre_process_time = 0.0; + real_t explosiveness_ratio = 0.0; + real_t randomness_ratio = 0.0; + real_t lifetime_randomness = 0.0; + real_t speed_scale = 1.0; bool local_coords; - int fixed_fps; - bool fractional_delta; + int fixed_fps = 0; + bool fractional_delta = true; Transform2D inv_emission_transform; - DrawOrder draw_order; + DrawOrder draw_order = DRAW_ORDER_INDEX; Ref<Texture2D> texture; //////// - Vector2 direction; - float spread; + Vector2 direction = Vector2(1, 0); + real_t spread = 45.0; - float parameters[PARAM_MAX]; - float randomness[PARAM_MAX]; + real_t parameters[PARAM_MAX]; + real_t randomness[PARAM_MAX]; Ref<Curve> curve_parameters[PARAM_MAX]; Color color; @@ -161,15 +161,15 @@ private: bool particle_flags[PARTICLE_FLAG_MAX]; - EmissionShape emission_shape; - float emission_sphere_radius; - Vector2 emission_rect_extents; + EmissionShape emission_shape = EMISSION_SHAPE_POINT; + real_t emission_sphere_radius = 1.0; + Vector2 emission_rect_extents = Vector2(1, 1); Vector<Vector2> emission_points; Vector<Vector2> emission_normals; Vector<Color> emission_colors; - int emission_point_count; + int emission_point_count = 0; - Vector2 gravity; + Vector2 gravity = Vector2(0, 98); void _update_internal(); void _particles_process(float p_delta); @@ -196,24 +196,24 @@ public: void set_lifetime(float p_lifetime); void set_one_shot(bool p_one_shot); void set_pre_process_time(float p_time); - void set_explosiveness_ratio(float p_ratio); - void set_randomness_ratio(float p_ratio); + void set_explosiveness_ratio(real_t p_ratio); + void set_randomness_ratio(real_t p_ratio); void set_lifetime_randomness(float p_random); void set_visibility_aabb(const Rect2 &p_aabb); void set_use_local_coordinates(bool p_enable); - void set_speed_scale(float p_scale); + void set_speed_scale(real_t p_scale); bool is_emitting() const; int get_amount() const; float get_lifetime() const; bool get_one_shot() const; float get_pre_process_time() const; - float get_explosiveness_ratio() const; - float get_randomness_ratio() const; + real_t get_explosiveness_ratio() const; + real_t get_randomness_ratio() const; float get_lifetime_randomness() const; Rect2 get_visibility_aabb() const; bool get_use_local_coordinates() const; - float get_speed_scale() const; + real_t get_speed_scale() const; void set_fixed_fps(int p_count); int get_fixed_fps() const; @@ -235,14 +235,14 @@ public: void set_direction(Vector2 p_direction); Vector2 get_direction() const; - void set_spread(float p_spread); - float get_spread() const; + void set_spread(real_t p_spread); + real_t get_spread() const; - void set_param(Parameter p_param, float p_value); - float get_param(Parameter p_param) const; + void set_param(Parameter p_param, real_t p_value); + real_t get_param(Parameter p_param) const; - void set_param_randomness(Parameter p_param, float p_value); - float get_param_randomness(Parameter p_param) const; + void set_param_randomness(Parameter p_param, real_t p_value); + real_t get_param_randomness(Parameter p_param) const; void set_param_curve(Parameter p_param, const Ref<Curve> &p_curve); Ref<Curve> get_param_curve(Parameter p_param) const; @@ -257,7 +257,7 @@ public: bool get_particle_flag(ParticleFlags p_particle_flag) const; void set_emission_shape(EmissionShape p_shape); - void set_emission_sphere_radius(float p_radius); + void set_emission_sphere_radius(real_t p_radius); void set_emission_rect_extents(Vector2 p_extents); void set_emission_points(const Vector<Vector2> &p_points); void set_emission_normals(const Vector<Vector2> &p_normals); @@ -265,7 +265,7 @@ public: void set_emission_point_count(int p_count); EmissionShape get_emission_shape() const; - float get_emission_sphere_radius() const; + real_t get_emission_sphere_radius() const; Vector2 get_emission_rect_extents() const; Vector<Vector2> get_emission_points() const; Vector<Vector2> get_emission_normals() const; diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp index 46096d7460..af70c47f7c 100644 --- a/scene/2d/gpu_particles_2d.cpp +++ b/scene/2d/gpu_particles_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -101,7 +101,6 @@ void GPUParticles2D::set_visibility_rect(const Rect2 &p_visibility_rect) { RS::get_singleton()->particles_set_custom_aabb(particles, aabb); - _change_notify("visibility_rect"); update(); } @@ -305,7 +304,7 @@ void GPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { if (one_shot && !is_emitting()) { - _change_notify(); + notify_property_list_changed(); set_process_internal(false); } } diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h index 0d1b82d93e..774cef9cc9 100644 --- a/scene/2d/gpu_particles_2d.h +++ b/scene/2d/gpu_particles_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index f5d13fd641..7d9cdd52ac 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,56 +32,79 @@ #include "core/config/engine.h" #include "physics_body_2d.h" +#include "scene/scene_string_names.h" #include "servers/physics_server_2d.h" -void Joint2D::_update_joint(bool p_only_free) { - if (joint.is_valid()) { - if (ba.is_valid() && bb.is_valid() && exclude_from_collision) { - PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false); - } +void Joint2D::_disconnect_signals() { + Node *node_a = get_node_or_null(a); + PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); + if (body_a) { + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + } - PhysicsServer2D::get_singleton()->free(joint); - joint = RID(); - ba = RID(); - bb = RID(); + Node *node_b = get_node_or_null(b); + PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); + if (body_b) { + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); } +} + +void Joint2D::_body_exit_tree() { + _disconnect_signals(); + _update_joint(true); +} + +void Joint2D::_update_joint(bool p_only_free) { + if (ba.is_valid() && bb.is_valid() && exclude_from_collision) { + PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, false); + } + + ba = RID(); + bb = RID(); + configured = false; if (p_only_free || !is_inside_tree()) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = String(); return; } - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)nullptr; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)nullptr; + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); if (node_a && !body_a && node_b && !body_b) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = TTR("Node A and Node B must be PhysicsBody2Ds"); update_configuration_warning(); return; } if (node_a && !body_a) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = TTR("Node A must be a PhysicsBody2D"); update_configuration_warning(); return; } if (node_b && !body_b) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = TTR("Node B must be a PhysicsBody2D"); update_configuration_warning(); return; } if (!body_a || !body_b) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = TTR("Joint is not connected to two PhysicsBody2Ds"); update_configuration_warning(); return; } if (body_a == body_b) { + PhysicsServer2D::get_singleton()->joint_clear(joint); warning = TTR("Node A and Node B must be different PhysicsBody2Ds"); update_configuration_warning(); return; @@ -90,7 +113,17 @@ void Joint2D::_update_joint(bool p_only_free) { warning = String(); update_configuration_warning(); - joint = _configure_joint(body_a, body_b); + if (body_a) { + body_a->force_update_transform(); + } + + if (body_b) { + body_b->force_update_transform(); + } + + configured = true; + + _configure_joint(joint, body_a, body_b); ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint."); @@ -99,6 +132,9 @@ void Joint2D::_update_joint(bool p_only_free) { ba = body_a->get_rid(); bb = body_b->get_rid(); + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree)); + PhysicsServer2D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); } @@ -107,6 +143,10 @@ void Joint2D::set_node_a(const NodePath &p_node_a) { return; } + if (joint.is_valid()) { + _disconnect_signals(); + } + a = p_node_a; _update_joint(); } @@ -119,6 +159,11 @@ void Joint2D::set_node_b(const NodePath &p_node_b) { if (b == p_node_b) { return; } + + if (joint.is_valid()) { + _disconnect_signals(); + } + b = p_node_b; _update_joint(); } @@ -134,6 +179,7 @@ void Joint2D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { + _disconnect_signals(); _update_joint(true); } } break; @@ -168,8 +214,8 @@ bool Joint2D::get_exclude_nodes_from_collision() const { String Joint2D::get_configuration_warning() const { String node_warning = Node2D::get_configuration_warning(); - if (!warning.empty()) { - if (!node_warning.empty()) { + if (!warning.is_empty()) { + if (!node_warning.is_empty()) { node_warning += "\n\n"; } node_warning += warning; @@ -198,8 +244,11 @@ void Joint2D::_bind_methods() { } Joint2D::Joint2D() { - bias = 0; - exclude_from_collision = true; + joint = PhysicsServer2D::get_singleton()->joint_create(); +} + +Joint2D::~Joint2D() { + PhysicsServer2D::get_singleton()->free(joint); } /////////////////////////////////////////////////////////////////////////////// @@ -223,16 +272,15 @@ void PinJoint2D::_notification(int p_what) { } } -RID PinJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { - RID pj = PhysicsServer2D::get_singleton()->pin_joint_create(get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID()); - PhysicsServer2D::get_singleton()->pin_joint_set_param(pj, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness); - return pj; +void PinJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { + PhysicsServer2D::get_singleton()->joint_make_pin(p_joint, get_global_transform().get_origin(), body_a->get_rid(), body_b ? body_b->get_rid() : RID()); + PhysicsServer2D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer2D::PIN_JOINT_SOFTNESS, softness); } void PinJoint2D::set_softness(real_t p_softness) { softness = p_softness; update(); - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness); } } @@ -249,7 +297,6 @@ void PinJoint2D::_bind_methods() { } PinJoint2D::PinJoint2D() { - softness = 0; } /////////////////////////////////////////////////////////////////////////////// @@ -275,13 +322,13 @@ void GrooveJoint2D::_notification(int p_what) { } } -RID GrooveJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { +void GrooveJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { Transform2D gt = get_global_transform(); Vector2 groove_A1 = gt.get_origin(); Vector2 groove_A2 = gt.xform(Vector2(0, length)); Vector2 anchor_B = gt.xform(Vector2(0, initial_offset)); - return PhysicsServer2D::get_singleton()->groove_joint_create(groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid()); + PhysicsServer2D::get_singleton()->joint_make_groove(p_joint, groove_A1, groove_A2, anchor_B, body_a->get_rid(), body_b->get_rid()); } void GrooveJoint2D::set_length(real_t p_length) { @@ -313,8 +360,6 @@ void GrooveJoint2D::_bind_methods() { } GrooveJoint2D::GrooveJoint2D() { - length = 50; - initial_offset = 25; } /////////////////////////////////////////////////////////////////////////////// @@ -339,19 +384,17 @@ void DampedSpringJoint2D::_notification(int p_what) { } } -RID DampedSpringJoint2D::_configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) { +void DampedSpringJoint2D::_configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) { Transform2D gt = get_global_transform(); Vector2 anchor_A = gt.get_origin(); Vector2 anchor_B = gt.xform(Vector2(0, length)); - RID dsj = PhysicsServer2D::get_singleton()->damped_spring_joint_create(anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid()); + PhysicsServer2D::get_singleton()->joint_make_damped_spring(p_joint, anchor_A, anchor_B, body_a->get_rid(), body_b->get_rid()); if (rest_length) { - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length); + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, rest_length); } - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness); - PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(dsj, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping); - - return dsj; + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_STIFFNESS, stiffness); + PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(p_joint, PhysicsServer2D::DAMPED_SPRING_DAMPING, damping); } void DampedSpringJoint2D::set_length(real_t p_length) { @@ -366,7 +409,7 @@ real_t DampedSpringJoint2D::get_length() const { void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) { rest_length = p_rest_length; update(); - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length); } } @@ -378,7 +421,7 @@ real_t DampedSpringJoint2D::get_rest_length() const { void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) { stiffness = p_stiffness; update(); - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness); } } @@ -390,7 +433,7 @@ real_t DampedSpringJoint2D::get_stiffness() const { void DampedSpringJoint2D::set_damping(real_t p_damping) { damping = p_damping; update(); - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping); } } @@ -416,8 +459,4 @@ void DampedSpringJoint2D::_bind_methods() { } DampedSpringJoint2D::DampedSpringJoint2D() { - length = 50; - rest_length = 0; - stiffness = 20; - damping = 1; } diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 759e7de8a0..08e02ee29d 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,19 +43,24 @@ class Joint2D : public Node2D { NodePath a; NodePath b; - real_t bias; + real_t bias = 0.0; - bool exclude_from_collision; + bool exclude_from_collision = true; + bool configured = false; String warning; protected: + void _disconnect_signals(); + void _body_exit_tree(); void _update_joint(bool p_only_free = false); void _notification(int p_what); - virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0; + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) = 0; static void _bind_methods(); + _FORCE_INLINE_ bool is_configured() const { return configured; } + public: virtual String get_configuration_warning() const override; @@ -73,16 +78,17 @@ public: RID get_joint() const { return joint; } Joint2D(); + ~Joint2D(); }; class PinJoint2D : public Joint2D { GDCLASS(PinJoint2D, Joint2D); - real_t softness; + real_t softness = 0.0; protected: void _notification(int p_what); - virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; static void _bind_methods(); public: @@ -95,12 +101,12 @@ public: class GrooveJoint2D : public Joint2D { GDCLASS(GrooveJoint2D, Joint2D); - real_t length; - real_t initial_offset; + real_t length = 50.0; + real_t initial_offset = 25.0; protected: void _notification(int p_what); - virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; static void _bind_methods(); public: @@ -116,14 +122,14 @@ public: class DampedSpringJoint2D : public Joint2D { GDCLASS(DampedSpringJoint2D, Joint2D); - real_t stiffness; - real_t damping; - real_t rest_length; - real_t length; + real_t stiffness = 20.0; + real_t damping = 1.0; + real_t rest_length = 0.0; + real_t length = 50.0; protected: void _notification(int p_what); - virtual RID _configure_joint(PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; + virtual void _configure_joint(RID p_joint, PhysicsBody2D *body_a, PhysicsBody2D *body_b) override; static void _bind_methods(); public: diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index 2b373a669b..99e35cad1d 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -84,21 +84,21 @@ Color Light2D::get_color() const { return color; } -void Light2D::set_height(float p_height) { +void Light2D::set_height(real_t p_height) { height = p_height; RS::get_singleton()->canvas_light_set_height(canvas_light, height); } -float Light2D::get_height() const { +real_t Light2D::get_height() const { return height; } -void Light2D::set_energy(float p_energy) { +void Light2D::set_energy(real_t p_energy) { energy = p_energy; RS::get_singleton()->canvas_light_set_energy(canvas_light, energy); } -float Light2D::get_energy() const { +real_t Light2D::get_energy() const { return energy; } @@ -159,6 +159,7 @@ int Light2D::get_item_shadow_cull_mask() const { void Light2D::set_shadow_enabled(bool p_enabled) { shadow = p_enabled; RS::get_singleton()->canvas_light_set_shadow_enabled(canvas_light, shadow); + notify_property_list_changed(); } bool Light2D::is_shadow_enabled() const { @@ -212,15 +213,21 @@ void Light2D::_notification(int p_what) { } } -void Light2D::set_shadow_smooth(float p_amount) { +void Light2D::set_shadow_smooth(real_t p_amount) { shadow_smooth = p_amount; RS::get_singleton()->canvas_light_set_shadow_smooth(canvas_light, shadow_smooth); } -float Light2D::get_shadow_smooth() const { +real_t Light2D::get_shadow_smooth() const { return shadow_smooth; } +void Light2D::_validate_property(PropertyInfo &property) const { + if (!shadow && (property.name == "shadow_color" || property.name == "shadow_filter" || property.name == "shadow_filter_smooth" || property.name == "shadow_item_cull_mask")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void Light2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &Light2D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &Light2D::is_enabled); @@ -300,22 +307,6 @@ void Light2D::_bind_methods() { Light2D::Light2D() { canvas_light = RenderingServer::get_singleton()->canvas_light_create(); - enabled = true; - editor_only = false; - shadow = false; - color = Color(1, 1, 1); - height = 0; - z_min = -1024; - z_max = 1024; - layer_min = 0; - layer_max = 0; - item_mask = 1; - item_shadow_mask = 1; - 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); } @@ -393,7 +384,6 @@ 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 { @@ -404,7 +394,7 @@ String PointLight2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!texture.is_valid()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("A texture with the shape of the light must be supplied to the \"Texture\" property."); @@ -413,7 +403,7 @@ String PointLight2D::get_configuration_warning() const { return warning; } -void PointLight2D::set_texture_scale(float p_scale) { +void PointLight2D::set_texture_scale(real_t p_scale) { _scale = p_scale; // Avoid having 0 scale values, can lead to errors in physics and rendering. if (_scale == 0) { @@ -423,7 +413,7 @@ void PointLight2D::set_texture_scale(float p_scale) { item_rect_changed(); } -float PointLight2D::get_texture_scale() const { +real_t PointLight2D::get_texture_scale() const { return _scale; } @@ -449,12 +439,12 @@ PointLight2D::PointLight2D() { ////////// -void DirectionalLight2D::set_max_distance(float p_distance) { +void DirectionalLight2D::set_max_distance(real_t p_distance) { max_distance = p_distance; RS::get_singleton()->canvas_light_set_directional_distance(_get_light(), max_distance); } -float DirectionalLight2D::get_max_distance() const { +real_t DirectionalLight2D::get_max_distance() const { return max_distance; } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 7dfeddc8e5..ae6cf6d0a0 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,24 +52,24 @@ public: private: RID canvas_light; - bool enabled; - bool editor_only; - bool shadow; - Color color; - Color shadow_color; - float height; - float energy; - int z_min; - int z_max; - int layer_min; - int layer_max; - int item_mask; - int item_shadow_mask; - float shadow_smooth; + bool enabled = true; + bool editor_only = false; + bool shadow = false; + Color color = Color(1, 1, 1); + Color shadow_color = Color(0, 0, 0, 0); + real_t height = 0.0; + real_t energy = 1.0; + int z_min = -1024; + int z_max = 1024; + int layer_min = 0; + int layer_max = 0; + int item_mask = 1; + int item_shadow_mask = 1; + real_t shadow_smooth = 0.0; Ref<Texture2D> texture; Vector2 texture_offset; - ShadowFilter shadow_filter; - BlendMode blend_mode; + ShadowFilter shadow_filter = SHADOW_FILTER_NONE; + BlendMode blend_mode = BLEND_MODE_ADD; void _update_light_visibility(); @@ -77,6 +77,7 @@ protected: _FORCE_INLINE_ RID _get_light() const { return canvas_light; } void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: void set_enabled(bool p_enabled); @@ -88,11 +89,11 @@ public: void set_color(const Color &p_color); Color get_color() const; - void set_height(float p_height); - float get_height() const; + void set_height(real_t p_height); + real_t get_height() const; - void set_energy(float p_energy); - float get_energy() const; + void set_energy(real_t p_energy); + real_t get_energy() const; void set_z_range_min(int p_min_z); int get_z_range_min() const; @@ -121,8 +122,8 @@ public: void set_shadow_color(const Color &p_shadow_color); Color get_shadow_color() const; - void set_shadow_smooth(float p_amount); - float get_shadow_smooth() const; + void set_shadow_smooth(real_t p_amount); + real_t get_shadow_smooth() const; void set_blend_mode(BlendMode p_mode); BlendMode get_blend_mode() const; @@ -138,7 +139,7 @@ class PointLight2D : public Light2D { GDCLASS(PointLight2D, Light2D); private: - float _scale = 1.0; + real_t _scale = 1.0; Ref<Texture2D> texture; Vector2 texture_offset; @@ -165,8 +166,8 @@ public: 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; + void set_texture_scale(real_t p_scale); + real_t get_texture_scale() const; String get_configuration_warning() const override; @@ -176,14 +177,14 @@ public: class DirectionalLight2D : public Light2D { GDCLASS(DirectionalLight2D, Light2D); - float max_distance = 10000.0; + real_t max_distance = 10000.0; protected: static void _bind_methods(); public: - void set_max_distance(float p_distance); - float get_max_distance() const; + void set_max_distance(real_t p_distance); + real_t get_max_distance() const; DirectionalLight2D(); }; diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index b5b39ccc8f..9589702e2e 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -145,9 +145,6 @@ void OccluderPolygon2D::_bind_methods() { OccluderPolygon2D::OccluderPolygon2D() { occ_polygon = RS::get_singleton()->canvas_occluder_polygon_create(); - closed = true; - cull = CULL_DISABLED; - rect_cache_dirty = true; } OccluderPolygon2D::~OccluderPolygon2D() { @@ -249,14 +246,14 @@ String LightOccluder2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!occluder_polygon.is_valid()) { - if (!warning.empty()) { + if (!warning.is_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) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The occluder polygon for this occluder is empty. Please draw a polygon."); diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index 97574af542..f567c6d965 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,11 +46,11 @@ public: private: RID occ_polygon; Vector<Vector2> polygon; - bool closed; - CullMode cull; + bool closed = true; + CullMode cull = CULL_DISABLED; mutable Rect2 item_rect; - mutable bool rect_cache_dirty; + mutable bool rect_cache_dirty = true; protected: static void _bind_methods(); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index e990e9f53e..37eb45c21d 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,15 +40,6 @@ VARIANT_ENUM_CAST(Line2D::LineCapMode) VARIANT_ENUM_CAST(Line2D::LineTextureMode) Line2D::Line2D() { - _joint_mode = LINE_JOINT_SHARP; - _begin_cap_mode = LINE_CAP_NONE; - _end_cap_mode = LINE_CAP_NONE; - _width = 10; - _default_color = Color(1, 1, 1); - _texture_mode = LINE_TEXTURE_NONE; - _sharp_limit = 2.f; - _round_precision = 8; - _antialiased = false; } #ifdef TOOLS_ENABLED @@ -125,6 +116,7 @@ Vector<Vector2> Line2D::get_points() const { } void Line2D::set_point_position(int i, Vector2 p_pos) { + ERR_FAIL_INDEX(i, _points.size()); _points.set(i, p_pos); update(); } diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 43739ee638..5e7eb4bac9 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -124,18 +124,18 @@ private: private: Vector<Vector2> _points; - LineJointMode _joint_mode; - LineCapMode _begin_cap_mode; - LineCapMode _end_cap_mode; - float _width; + LineJointMode _joint_mode = LINE_JOINT_SHARP; + LineCapMode _begin_cap_mode = LINE_CAP_NONE; + LineCapMode _end_cap_mode = LINE_CAP_NONE; + float _width = 10.0; Ref<Curve> _curve; - Color _default_color; + Color _default_color = Color(1, 1, 1); Ref<Gradient> _gradient; Ref<Texture2D> _texture; - LineTextureMode _texture_mode; - float _sharp_limit; - int _round_precision; - bool _antialiased; + LineTextureMode _texture_mode = LINE_TEXTURE_NONE; + float _sharp_limit = 2.f; + int _round_precision = 8; + bool _antialiased = false; }; #endif // LINE2D_H diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index e0116d9bad..c478f03356 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -94,20 +94,6 @@ static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) { //---------------------------------------------------------------------------- LineBuilder::LineBuilder() { - joint_mode = Line2D::LINE_JOINT_SHARP; - width = 10; - curve = nullptr; - default_color = Color(0.4, 0.5, 1); - gradient = nullptr; - sharp_limit = 2.f; - round_precision = 8; - begin_cap_mode = Line2D::LINE_CAP_NONE; - end_cap_mode = Line2D::LINE_CAP_NONE; - tile_aspect = 1.f; - - _interpolate_color = false; - _last_index[0] = 0; - _last_index[1] = 0; } void LineBuilder::clear_output() { @@ -389,7 +375,7 @@ void LineBuilder::build() { } if (intersection_result != SEGMENT_INTERSECT) { - // In this case the joint is too corrputed to be re-used, + // In this case the joint is too corrupted to be re-used, // start again the strip with fallback points strip_begin(pos_up0, pos_down0, color1, uvx1); } @@ -499,7 +485,7 @@ void LineBuilder::strip_add_tri(Vector2 up, Orientation orientation) { if (texture_mode != Line2D::LINE_TEXTURE_NONE) { // UVs are just one slice of the texture all along - // (otherwise we can't share the bottom vertice) + // (otherwise we can't share the bottom vertex) uvs.push_back(uvs[_last_index[opposite_orientation]]); } @@ -534,7 +520,7 @@ void LineBuilder::strip_add_arc(Vector2 center, float angle_delta, Orientation o strip_add_tri(rpos, orientation); } - // Last arc vertice + // Last arc vertex rpos = center + Vector2(Math::cos(end_angle), Math::sin(end_angle)) * radius; strip_add_tri(rpos, orientation); } @@ -554,7 +540,7 @@ void LineBuilder::new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Col float t = Vector2(1, 0).angle_to(vbegin); float end_angle = t + angle_delta; Vector2 rpos(0, 0); - float tt_begin = -Math_PI / 2.f; + float tt_begin = -Math_PI / 2.0f; float tt = tt_begin; // Center vertice @@ -583,7 +569,7 @@ void LineBuilder::new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Col } } - // Last arc vertice + // Last arc vertex Vector2 sc = Vector2(Math::cos(end_angle), Math::sin(end_angle)); rpos = center + sc * radius; vertices.push_back(rpos); diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h index 0e033d9be1..654e61422b 100644 --- a/scene/2d/line_builder.h +++ b/scene/2d/line_builder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,17 +41,17 @@ public: // TODO Move in a struct and reference it // Input Vector<Vector2> points; - Line2D::LineJointMode joint_mode; - Line2D::LineCapMode begin_cap_mode; - Line2D::LineCapMode end_cap_mode; - float width; - Curve *curve; - Color default_color; - Gradient *gradient; - Line2D::LineTextureMode texture_mode; - float sharp_limit; - int round_precision; - float tile_aspect; // w/h + Line2D::LineJointMode joint_mode = Line2D::LINE_JOINT_SHARP; + Line2D::LineCapMode begin_cap_mode = Line2D::LINE_CAP_NONE; + Line2D::LineCapMode end_cap_mode = Line2D::LINE_CAP_NONE; + float width = 10.0; + Curve *curve = nullptr; + Color default_color = Color(0.4, 0.5, 1); + Gradient *gradient = nullptr; + Line2D::LineTextureMode texture_mode = Line2D::LineTextureMode::LINE_TEXTURE_NONE; + float sharp_limit = 2.f; + int round_precision = 8; + float tile_aspect = 1.f; // w/h // TODO offset_joints option (offers alternative implementation of round joints) // TODO Move in a struct and reference it @@ -82,8 +82,8 @@ private: void new_arc(Vector2 center, Vector2 vbegin, float angle_delta, Color color, Rect2 uv_rect); private: - bool _interpolate_color; - int _last_index[2]; // Index of last up and down vertices of the strip + bool _interpolate_color = false; + int _last_index[2] = {}; // Index of last up and down vertices of the strip }; #endif // LINE_BUILDER_H diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp index 037e423ce9..b7a0028199 100644 --- a/scene/2d/mesh_instance_2d.cpp +++ b/scene/2d/mesh_instance_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,7 +71,6 @@ void MeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; update(); emit_signal("texture_changed"); - _change_notify("texture"); } void MeshInstance2D::set_normal_map(const Ref<Texture2D> &p_texture) { diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h index f10ab17a7c..adfda4cf7f 100644 --- a/scene/2d/mesh_instance_2d.h +++ b/scene/2d/mesh_instance_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/2d/multimesh_instance_2d.cpp b/scene/2d/multimesh_instance_2d.cpp index c258e30eab..72a899370e 100644 --- a/scene/2d/multimesh_instance_2d.cpp +++ b/scene/2d/multimesh_instance_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,7 +71,6 @@ void MultiMeshInstance2D::set_texture(const Ref<Texture2D> &p_texture) { texture = p_texture; update(); emit_signal("texture_changed"); - _change_notify("texture"); } Ref<Texture2D> MultiMeshInstance2D::get_texture() const { diff --git a/scene/2d/multimesh_instance_2d.h b/scene/2d/multimesh_instance_2d.h index aadedac42a..213cbd19b0 100644 --- a/scene/2d/multimesh_instance_2d.h +++ b/scene/2d/multimesh_instance_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/2d/navigation_2d.cpp b/scene/2d/navigation_2d.cpp deleted file mode 100644 index 039c6f2e53..0000000000 --- a/scene/2d/navigation_2d.cpp +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************/ -/* navigation_2d.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 "navigation_2d.h" -#include "servers/navigation_server_2d.h" - -void Navigation2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_rid"), &Navigation2D::get_rid); - - ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation2D::get_simple_path, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation2D::get_closest_point); - ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation2D::get_closest_point_owner); - - ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation2D::set_cell_size); - ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation2D::get_cell_size); - - ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation2D::set_edge_connection_margin); - ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation2D::get_edge_connection_margin); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size"), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_connection_margin"), "set_edge_connection_margin", "get_edge_connection_margin"); -} - -void Navigation2D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - NavigationServer2D::get_singleton()->map_set_active(map, true); - } break; - case NOTIFICATION_EXIT_TREE: { - NavigationServer2D::get_singleton()->map_set_active(map, false); - } break; - } -} - -void Navigation2D::set_cell_size(float p_cell_size) { - cell_size = p_cell_size; - NavigationServer2D::get_singleton()->map_set_cell_size(map, cell_size); -} - -void Navigation2D::set_edge_connection_margin(float p_edge_connection_margin) { - edge_connection_margin = p_edge_connection_margin; - NavigationServer2D::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin); -} - -Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize) const { - return NavigationServer2D::get_singleton()->map_get_path(map, p_start, p_end, p_optimize); -} - -Vector2 Navigation2D::get_closest_point(const Vector2 &p_point) const { - return NavigationServer2D::get_singleton()->map_get_closest_point(map, p_point); -} - -RID Navigation2D::get_closest_point_owner(const Vector2 &p_point) const { - return NavigationServer2D::get_singleton()->map_get_closest_point_owner(map, p_point); -} - -Navigation2D::Navigation2D() { - map = NavigationServer2D::get_singleton()->map_create(); - set_cell_size(10); // Ten pixels - set_edge_connection_margin(100); -} - -Navigation2D::~Navigation2D() { - NavigationServer2D::get_singleton()->free(map); -} diff --git a/scene/2d/navigation_2d.h b/scene/2d/navigation_2d.h deleted file mode 100644 index 6046bddb32..0000000000 --- a/scene/2d/navigation_2d.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/* navigation_2d.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 NAVIGATION_2D_H -#define NAVIGATION_2D_H - -#include "scene/2d/navigation_region_2d.h" -#include "scene/2d/node_2d.h" - -class Navigation2D : public Node2D { - GDCLASS(Navigation2D, Node2D); - - RID map; - real_t cell_size; - real_t edge_connection_margin; - -protected: - static void _bind_methods(); - void _notification(int p_what); - -public: - RID get_rid() const { - return map; - } - - void set_cell_size(float p_cell_size); - float get_cell_size() const { - return cell_size; - } - - void set_edge_connection_margin(float p_edge_connection_margin); - float get_edge_connection_margin() const { - return edge_connection_margin; - } - - Vector<Vector2> get_simple_path(const Vector2 &p_start, const Vector2 &p_end, bool p_optimize = true) const; - Vector2 get_closest_point(const Vector2 &p_point) const; - RID get_closest_point_owner(const Vector2 &p_point) const; - - Navigation2D(); - ~Navigation2D(); -}; - -#endif // NAVIGATION_2D_H diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp index 1c7063d0d3..064fcc91a4 100644 --- a/scene/2d/navigation_agent_2d.cpp +++ b/scene/2d/navigation_agent_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,7 +32,6 @@ #include "core/config/engine.h" #include "core/math/geometry_2d.h" -#include "scene/2d/navigation_2d.h" #include "servers/navigation_server_2d.h" void NavigationAgent2D::_bind_methods() { @@ -42,9 +41,6 @@ void NavigationAgent2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_radius", "radius"), &NavigationAgent2D::set_radius); ClassDB::bind_method(D_METHOD("get_radius"), &NavigationAgent2D::get_radius); - ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent2D::set_navigation_node); - ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent2D::get_navigation_node); - ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent2D::set_neighbor_dist); ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent2D::get_neighbor_dist); @@ -95,27 +91,10 @@ void NavigationAgent2D::_notification(int p_what) { NavigationServer2D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); - // Search the navigation node and set it - { - Navigation2D *nav = nullptr; - Node *p = get_parent(); - while (p != nullptr) { - nav = Object::cast_to<Navigation2D>(p); - if (nav != nullptr) { - p = nullptr; - } else { - p = p->get_parent(); - } - } - - set_navigation(nav); - } - set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { agent_parent = nullptr; - set_navigation(nullptr); set_physics_process_internal(false); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -146,23 +125,13 @@ NavigationAgent2D::~NavigationAgent2D() { agent = RID(); // Pointless } -void NavigationAgent2D::set_navigation(Navigation2D *p_nav) { - if (navigation == p_nav) { - return; // Pointless - } - - navigation = p_nav; - NavigationServer2D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); -} - -void NavigationAgent2D::set_navigation_node(Node *p_nav) { - Navigation2D *nav = Object::cast_to<Navigation2D>(p_nav); - ERR_FAIL_COND(nav == nullptr); - set_navigation(nav); +void NavigationAgent2D::set_navigable_layers(uint32_t p_layers) { + navigable_layers = p_layers; + update_navigation(); } -Node *NavigationAgent2D::get_navigation_node() const { - return Object::cast_to<Node>(navigation); +uint32_t NavigationAgent2D::get_navigable_layers() const { + return navigable_layers; } void NavigationAgent2D::set_target_desired_distance(real_t p_dd) { @@ -274,7 +243,7 @@ String NavigationAgent2D::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!Object::cast_to<Node2D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The NavigationAgent2D can be used only under a Node2D node"); @@ -287,7 +256,7 @@ void NavigationAgent2D::update_navigation() { if (agent_parent == nullptr) { return; } - if (navigation == nullptr) { + if (!agent_parent->is_inside_tree()) { return; } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { @@ -319,7 +288,7 @@ void NavigationAgent2D::update_navigation() { } if (reload_path) { - navigation_path = NavigationServer2D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true); + navigation_path = NavigationServer2D::get_singleton()->map_get_path(agent_parent->get_world_2d()->get_navigation_map(), o, target_location, true, navigable_layers); navigation_finished = false; nav_path_index = 0; emit_signal("path_changed"); diff --git a/scene/2d/navigation_agent_2d.h b/scene/2d/navigation_agent_2d.h index 1f2377837b..153ede8cec 100644 --- a/scene/2d/navigation_agent_2d.h +++ b/scene/2d/navigation_agent_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,16 +35,16 @@ #include "scene/main/node.h" class Node2D; -class Navigation2D; class NavigationAgent2D : public Node { GDCLASS(NavigationAgent2D, Node); Node2D *agent_parent = nullptr; - Navigation2D *navigation = nullptr; RID agent; + uint32_t navigable_layers = 1; + real_t target_desired_distance = 1.0; real_t radius; real_t neighbor_dist; @@ -74,18 +74,13 @@ public: NavigationAgent2D(); virtual ~NavigationAgent2D(); - void set_navigation(Navigation2D *p_nav); - const Navigation2D *get_navigation() const { - return navigation; - } - - void set_navigation_node(Node *p_nav); - Node *get_navigation_node() const; - RID get_rid() const { return agent; } + void set_navigable_layers(uint32_t p_layers); + uint32_t get_navigable_layers() const; + void set_target_desired_distance(real_t p_dd); real_t get_target_desired_distance() const { return target_desired_distance; diff --git a/scene/2d/navigation_obstacle_2d.cpp b/scene/2d/navigation_obstacle_2d.cpp index 252d7cbb96..965e2b6dc1 100644 --- a/scene/2d/navigation_obstacle_2d.cpp +++ b/scene/2d/navigation_obstacle_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,48 +31,31 @@ #include "navigation_obstacle_2d.h" #include "scene/2d/collision_shape_2d.h" -#include "scene/2d/navigation_2d.h" #include "scene/2d/physics_body_2d.h" #include "servers/navigation_server_2d.h" void NavigationObstacle2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle2D::set_navigation_node); - ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle2D::get_navigation_node); } void NavigationObstacle2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - update_agent_shape(); - - // Search the navigation node and set it - { - Navigation2D *nav = nullptr; - Node *p = get_parent(); - while (p != nullptr) { - nav = Object::cast_to<Navigation2D>(p); - if (nav != nullptr) { - p = nullptr; - } else { - p = p->get_parent(); - } - } - - set_navigation(nav); - } - set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { - set_navigation(nullptr); set_physics_process_internal(false); } break; + case NOTIFICATION_PARENTED: { + parent_node2d = Object::cast_to<Node2D>(get_parent()); + update_agent_shape(); + } break; + case NOTIFICATION_UNPARENTED: { + parent_node2d = nullptr; + } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - Node2D *node = Object::cast_to<Node2D>(get_parent()); - if (node) { - NavigationServer2D::get_singleton()->agent_set_position(agent, node->get_global_transform().get_origin()); + if (parent_node2d) { + NavigationServer2D::get_singleton()->agent_set_position(agent, parent_node2d->get_global_transform().get_origin()); } - } break; } } @@ -86,30 +69,11 @@ NavigationObstacle2D::~NavigationObstacle2D() { agent = RID(); // Pointless } -void NavigationObstacle2D::set_navigation(Navigation2D *p_nav) { - if (navigation == p_nav) { - return; // Pointless - } - - navigation = p_nav; - NavigationServer2D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); -} - -void NavigationObstacle2D::set_navigation_node(Node *p_nav) { - Navigation2D *nav = Object::cast_to<Navigation2D>(p_nav); - ERR_FAIL_COND(nav == nullptr); - set_navigation(nav); -} - -Node *NavigationObstacle2D::get_navigation_node() const { - return Object::cast_to<Node>(navigation); -} - String NavigationObstacle2D::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!Object::cast_to<Node2D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The NavigationObstacle2D only serves to provide collision avoidance to a Node2D object."); @@ -119,40 +83,37 @@ String NavigationObstacle2D::get_configuration_warning() const { } void NavigationObstacle2D::update_agent_shape() { - Node *node = get_parent(); - - // Estimate the radius of this physics body - real_t radius = 0.0; - for (int i(0); i < node->get_child_count(); i++) { - // For each collision shape - CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(node->get_child(i)); - if (cs) { - // Take the distance between the Body center to the shape center - real_t r = cs->get_transform().get_origin().length(); - if (cs->get_shape().is_valid()) { - // and add the enclosing shape radius - r += cs->get_shape()->get_enclosing_radius(); + if (parent_node2d) { + // Estimate the radius of this physics body + real_t radius = 0.0; + for (int i(0); i < parent_node2d->get_child_count(); i++) { + // For each collision shape + CollisionShape2D *cs = Object::cast_to<CollisionShape2D>(parent_node2d->get_child(i)); + if (cs) { + // Take the distance between the Body center to the shape center + real_t r = cs->get_transform().get_origin().length(); + if (cs->get_shape().is_valid()) { + // and add the enclosing shape radius + r += cs->get_shape()->get_enclosing_radius(); + } + Size2 s = cs->get_global_transform().get_scale(); + r *= MAX(s.x, s.y); + // Takes the biggest radius + radius = MAX(radius, r); } - Size2 s = cs->get_global_transform().get_scale(); - r *= MAX(s.x, s.y); - // Takes the biggest radius - radius = MAX(radius, r); } - } - Node2D *node_2d = Object::cast_to<Node2D>(node); - if (node_2d) { - Vector2 s = node_2d->get_global_transform().get_scale(); + Vector2 s = parent_node2d->get_global_transform().get_scale(); radius *= MAX(s.x, s.y); - } - if (radius == 0.0) { - radius = 1.0; // Never a 0 radius - } + if (radius == 0.0) { + radius = 1.0; // Never a 0 radius + } - // Initialize the Agent as an object - NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0); - NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0); - NavigationServer2D::get_singleton()->agent_set_radius(agent, radius); - NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0); + // Initialize the Agent as an object + NavigationServer2D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); + NavigationServer2D::get_singleton()->agent_set_max_neighbors(agent, 0); + NavigationServer2D::get_singleton()->agent_set_time_horizon(agent, 0.0); + NavigationServer2D::get_singleton()->agent_set_radius(agent, radius); + NavigationServer2D::get_singleton()->agent_set_max_speed(agent, 0.0); + } } diff --git a/scene/2d/navigation_obstacle_2d.h b/scene/2d/navigation_obstacle_2d.h index d65f44bc0e..135ca4651e 100644 --- a/scene/2d/navigation_obstacle_2d.h +++ b/scene/2d/navigation_obstacle_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,15 +31,13 @@ #ifndef NAVIGATION_OBSTACLE_2D_H #define NAVIGATION_OBSTACLE_2D_H +#include "scene/2d/node_2d.h" #include "scene/main/node.h" -class Navigation2D; - class NavigationObstacle2D : public Node { GDCLASS(NavigationObstacle2D, Node); - Navigation2D *navigation = nullptr; - + Node2D *parent_node2d = nullptr; RID agent; protected: @@ -50,14 +48,6 @@ public: NavigationObstacle2D(); virtual ~NavigationObstacle2D(); - void set_navigation(Navigation2D *p_nav); - const Navigation2D *get_navigation() const { - return navigation; - } - - void set_navigation_node(Node *p_nav); - Node *get_navigation_node() const; - RID get_rid() const { return agent; } diff --git a/scene/2d/navigation_region_2d.cpp b/scene/2d/navigation_region_2d.cpp index 98817ec03e..8be8c8db4a 100644 --- a/scene/2d/navigation_region_2d.cpp +++ b/scene/2d/navigation_region_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,10 +34,9 @@ #include "core/core_string_names.h" #include "core/math/geometry_2d.h" #include "core/os/mutex.h" -#include "navigation_2d.h" #include "servers/navigation_server_2d.h" -#include "thirdparty/misc/triangulator.h" +#include "thirdparty/misc/polypartition.h" #ifdef TOOLS_ENABLED Rect2 NavigationPolygon::_edit_get_rect() const { @@ -228,7 +227,7 @@ void NavigationPolygon::make_polygons_from_outlines() { MutexLock lock(navmesh_generation); navmesh.unref(); } - List<TriangulatorPoly> in_poly, out_poly; + List<TPPLPoly> in_poly, out_poly; Vector2 outside_point(-1e10, -1e10); @@ -278,23 +277,23 @@ void NavigationPolygon::make_polygons_from_outlines() { bool outer = (interscount % 2) == 0; - TriangulatorPoly tp; + TPPLPoly tp; tp.Init(olsize); for (int j = 0; j < olsize; j++) { tp[j] = r[j]; } if (outer) { - tp.SetOrientation(TRIANGULATOR_CCW); + tp.SetOrientation(TPPL_ORIENTATION_CCW); } else { - tp.SetOrientation(TRIANGULATOR_CW); + tp.SetOrientation(TPPL_ORIENTATION_CW); tp.SetHole(true); } in_poly.push_back(tp); } - TriangulatorPartition tpart; + TPPLPartition tpart; if (tpart.ConvexPartition_HM(&in_poly, &out_poly) == 0) { //failed! ERR_PRINT("NavigationPolygon: Convex partition failed!"); return; @@ -304,8 +303,8 @@ void NavigationPolygon::make_polygons_from_outlines() { vertices.resize(0); Map<Vector2, int> points; - for (List<TriangulatorPoly>::Element *I = out_poly.front(); I; I = I->next()) { - TriangulatorPoly &tp = I->get(); + for (List<TPPLPoly>::Element *I = out_poly.front(); I; I = I->next()) { + TPPLPoly &tp = I->get(); struct Polygon p; @@ -365,10 +364,10 @@ void NavigationRegion2D::set_enabled(bool p_enabled) { if (!enabled) { NavigationServer2D::get_singleton()->region_set_map(region, RID()); + NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } else { - if (navigation) { - NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid()); - } + NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); + NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } if (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) { @@ -380,6 +379,14 @@ bool NavigationRegion2D::is_enabled() const { return enabled; } +void NavigationRegion2D::set_layers(uint32_t p_layers) { + NavigationServer2D::get_singleton()->region_set_layers(region, p_layers); +} + +uint32_t NavigationRegion2D::get_layers() const { + return NavigationServer2D::get_singleton()->region_get_layers(region); +} + ///////////////////////////// #ifdef TOOLS_ENABLED Rect2 NavigationRegion2D::_edit_get_rect() const { @@ -394,35 +401,24 @@ bool NavigationRegion2D::_edit_is_selected_on_click(const Point2 &p_point, doubl void NavigationRegion2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - Node2D *c = this; - while (c) { - navigation = Object::cast_to<Navigation2D>(c); - if (navigation) { - if (enabled) { - NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid()); - } - break; - } - - c = Object::cast_to<Node2D>(c->get_parent()); + if (enabled) { + NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); + NavigationServer2D::get_singleton()->connect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } - } break; case NOTIFICATION_TRANSFORM_CHANGED: { NavigationServer2D::get_singleton()->region_set_transform(region, get_global_transform()); - } break; case NOTIFICATION_EXIT_TREE: { - if (navigation) { - NavigationServer2D::get_singleton()->region_set_map(region, RID()); + NavigationServer2D::get_singleton()->region_set_map(region, RID()); + if (enabled) { + NavigationServer2D::get_singleton()->disconnect("map_changed", callable_mp(this, &NavigationRegion2D::_map_changed)); } - navigation = nullptr; } break; case NOTIFICATION_DRAW: { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { Vector<Vector2> verts = navpoly->get_vertices(); - int vsize = verts.size(); - if (vsize < 3) { + if (verts.size() < 3) { return; } @@ -432,33 +428,47 @@ void NavigationRegion2D::_notification(int p_what) { } else { color = get_tree()->get_debug_navigation_disabled_color(); } - Vector<Color> colors; - Vector<Vector2> vertices; - vertices.resize(vsize); - colors.resize(vsize); - { - const Vector2 *vr = verts.ptr(); - for (int i = 0; i < vsize; i++) { - vertices.write[i] = vr[i]; - colors.write[i] = color; - } - } + Color doors_color = color.lightened(0.2); - Vector<int> indices; + RandomPCG rand; for (int i = 0; i < navpoly->get_polygon_count(); i++) { + // An array of vertices for this polygon. Vector<int> polygon = navpoly->get_polygon(i); - - for (int j = 2; j < polygon.size(); j++) { - int kofs[3] = { 0, j - 1, j }; - for (int k = 0; k < 3; k++) { - int idx = polygon[kofs[k]]; - ERR_FAIL_INDEX(idx, vsize); - indices.push_back(idx); - } + Vector<Vector2> vertices; + vertices.resize(polygon.size()); + for (int j = 0; j < polygon.size(); j++) { + ERR_FAIL_INDEX(polygon[j], verts.size()); + vertices.write[j] = verts[polygon[j]]; } + + // Generate the polygon color, slightly randomly modified from the settings one. + Color random_variation_color; + random_variation_color.set_hsv(color.get_h() + rand.random(-1.0, 1.0) * 0.05, color.get_s(), color.get_v() + rand.random(-1.0, 1.0) * 0.1); + random_variation_color.a = color.a; + Vector<Color> colors; + colors.push_back(random_variation_color); + + RS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), vertices, colors); + } + + // Draw the region + Transform2D xform = get_global_transform(); + const NavigationServer2D *ns = NavigationServer2D::get_singleton(); + float radius = ns->map_get_edge_connection_margin(get_world_2d()->get_navigation_map()) / 2.0; + for (int i = 0; i < ns->region_get_connections_count(region); i++) { + // Two main points + Vector2 a = ns->region_get_connection_pathway_start(region, i); + a = xform.affine_inverse().xform(a); + Vector2 b = ns->region_get_connection_pathway_end(region, i); + b = xform.affine_inverse().xform(b); + draw_line(a, b, doors_color); + + // Draw a circle to illustrate the margins. + float angle = (b - a).angle(); + draw_arc(a, radius, angle + Math_PI / 2.0, angle - Math_PI / 2.0 + Math_TAU, 10, doors_color); + draw_arc(b, radius, angle - Math_PI / 2.0, angle + Math_PI / 2.0, 10, doors_color); } - RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, vertices, colors); } } break; } @@ -481,7 +491,6 @@ void NavigationRegion2D::set_navigation_polygon(const Ref<NavigationPolygon> &p_ } _navpoly_changed(); - _change_notify("navpoly"); update_configuration_warning(); } @@ -494,6 +503,11 @@ void NavigationRegion2D::_navpoly_changed() { update(); } } +void NavigationRegion2D::_map_changed(RID p_map) { + if (enabled && get_world_2d()->get_navigation_map() == p_map) { + update(); + } +} String NavigationRegion2D::get_configuration_warning() const { if (!is_visible_in_tree() || !is_inside_tree()) { @@ -503,23 +517,13 @@ String NavigationRegion2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!navpoly.is_valid()) { - if (!warning.empty()) { + if (!warning.is_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 warning; - } - c = Object::cast_to<Node2D>(c->get_parent()); - } - 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."); + return warning; } void NavigationRegion2D::_bind_methods() { @@ -529,10 +533,14 @@ void NavigationRegion2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion2D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion2D::is_enabled); + ClassDB::bind_method(D_METHOD("set_layers", "layers"), &NavigationRegion2D::set_layers); + ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion2D::get_layers); + ClassDB::bind_method(D_METHOD("_navpoly_changed"), &NavigationRegion2D::_navpoly_changed); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navpoly", PROPERTY_HINT_RESOURCE_TYPE, "NavigationPolygon"), "set_navigation_polygon", "get_navigation_polygon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_2D_NAVIGATION), "set_layers", "get_layers"); } NavigationRegion2D::NavigationRegion2D() { diff --git a/scene/2d/navigation_region_2d.h b/scene/2d/navigation_region_2d.h index ba92d27a95..58f04599be 100644 --- a/scene/2d/navigation_region_2d.h +++ b/scene/2d/navigation_region_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -91,17 +91,15 @@ public: ~NavigationPolygon() {} }; -class Navigation2D; - class NavigationRegion2D : public Node2D { GDCLASS(NavigationRegion2D, Node2D); bool enabled = true; RID region; - Navigation2D *navigation = nullptr; Ref<NavigationPolygon> navpoly; void _navpoly_changed(); + void _map_changed(RID p_RID); protected: void _notification(int p_what); @@ -116,6 +114,9 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; + void set_layers(uint32_t p_layers); + uint32_t get_layers() const; + void set_navigation_polygon(const Ref<NavigationPolygon> &p_navpoly); Ref<NavigationPolygon> get_navigation_polygon() const; diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index a2f687cd96..8afc43ddc9 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -53,12 +53,6 @@ void Node2D::_edit_set_state(const Dictionary &p_state) { skew = p_state["skew"]; _update_transform(); - _change_notify("rotation"); - _change_notify("rotation_degrees"); - _change_notify("scale"); - _change_notify("skew"); - _change_notify("skew_degrees"); - _change_notify("position"); } void Node2D::_edit_set_position(const Point2 &p_position) { @@ -77,14 +71,12 @@ Size2 Node2D::_edit_get_scale() const { return _scale; } -void Node2D::_edit_set_rotation(float p_rotation) { +void Node2D::_edit_set_rotation(real_t p_rotation) { angle = p_rotation; _update_transform(); - _change_notify("rotation"); - _change_notify("rotation_degrees"); } -float Node2D::_edit_get_rotation() const { +real_t Node2D::_edit_get_rotation() const { return angle; } @@ -124,8 +116,6 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) { _scale *= new_scale; _update_transform(); - _change_notify("scale"); - _change_notify("position"); } #endif @@ -156,34 +146,29 @@ void Node2D::set_position(const Point2 &p_pos) { } pos = p_pos; _update_transform(); - _change_notify("position"); } -void Node2D::set_rotation(float p_radians) { +void Node2D::set_rotation(real_t p_radians) { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); } angle = p_radians; _update_transform(); - _change_notify("rotation"); - _change_notify("rotation_degrees"); } -void Node2D::set_skew(float p_radians) { +void Node2D::set_skew(real_t p_radians) { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); } skew = p_radians; _update_transform(); - _change_notify("skew"); - _change_notify("skew_degrees"); } -void Node2D::set_rotation_degrees(float p_degrees) { +void Node2D::set_rotation_degrees(real_t p_degrees) { set_rotation(Math::deg2rad(p_degrees)); } -void Node2D::set_skew_degrees(float p_degrees) { +void Node2D::set_skew_degrees(real_t p_degrees) { set_skew(Math::deg2rad(p_degrees)); } @@ -200,7 +185,6 @@ void Node2D::set_scale(const Size2 &p_scale) { _scale.y = CMP_EPSILON; } _update_transform(); - _change_notify("scale"); } Point2 Node2D::get_position() const { @@ -210,7 +194,7 @@ Point2 Node2D::get_position() const { return pos; } -float Node2D::get_rotation() const { +real_t Node2D::get_rotation() const { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); } @@ -218,7 +202,7 @@ float Node2D::get_rotation() const { return angle; } -float Node2D::get_skew() const { +real_t Node2D::get_skew() const { if (_xform_dirty) { ((Node2D *)this)->_update_xform_values(); } @@ -226,11 +210,11 @@ float Node2D::get_skew() const { return skew; } -float Node2D::get_rotation_degrees() const { +real_t Node2D::get_rotation_degrees() const { return Math::rad2deg(get_rotation()); } -float Node2D::get_skew_degrees() const { +real_t Node2D::get_skew_degrees() const { return Math::rad2deg(get_skew()); } @@ -246,7 +230,7 @@ Transform2D Node2D::get_transform() const { return _mat; } -void Node2D::rotate(float p_radians) { +void Node2D::rotate(real_t p_radians) { set_rotation(get_rotation() + p_radians); } @@ -262,7 +246,7 @@ void Node2D::apply_scale(const Size2 &p_amount) { set_scale(get_scale() * p_amount); } -void Node2D::move_x(float p_delta, bool p_scaled) { +void Node2D::move_x(real_t p_delta, bool p_scaled) { Transform2D t = get_transform(); Vector2 m = t[0]; if (!p_scaled) { @@ -271,7 +255,7 @@ void Node2D::move_x(float p_delta, bool p_scaled) { set_position(t[2] + m * p_delta); } -void Node2D::move_y(float p_delta, bool p_scaled) { +void Node2D::move_y(real_t p_delta, bool p_scaled) { Transform2D t = get_transform(); Vector2 m = t[1]; if (!p_scaled) { @@ -295,25 +279,25 @@ void Node2D::set_global_position(const Point2 &p_pos) { } } -float Node2D::get_global_rotation() const { +real_t Node2D::get_global_rotation() const { return get_global_transform().get_rotation(); } -void Node2D::set_global_rotation(float p_radians) { +void Node2D::set_global_rotation(real_t p_radians) { CanvasItem *pi = get_parent_item(); if (pi) { - const float parent_global_rot = pi->get_global_transform().get_rotation(); + const real_t parent_global_rot = pi->get_global_transform().get_rotation(); set_rotation(p_radians - parent_global_rot); } else { set_rotation(p_radians); } } -float Node2D::get_global_rotation_degrees() const { +real_t Node2D::get_global_rotation_degrees() const { return Math::rad2deg(get_global_rotation()); } -void Node2D::set_global_rotation_degrees(float p_degrees) { +void Node2D::set_global_rotation_degrees(real_t p_degrees) { set_global_rotation(Math::deg2rad(p_degrees)); } @@ -358,7 +342,6 @@ void Node2D::set_z_index(int p_z) { ERR_FAIL_COND(p_z > RS::CANVAS_ITEM_Z_MAX); z_index = p_z; RS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index); - _change_notify("z_index"); } void Node2D::set_z_as_relative(bool p_enabled) { @@ -396,7 +379,7 @@ void Node2D::look_at(const Vector2 &p_pos) { rotate(get_angle_to(p_pos)); } -float Node2D::get_angle_to(const Vector2 &p_pos) const { +real_t Node2D::get_angle_to(const Vector2 &p_pos) const { return (to_local(p_pos) * get_scale()).angle(); } diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index a66e7f625d..358b7e6520 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,9 +37,9 @@ class Node2D : public CanvasItem { GDCLASS(Node2D, CanvasItem); Point2 pos; - float angle = 0; + real_t angle = 0.0; Size2 _scale = Vector2(1, 1); - float skew = 0; + real_t skew = 0.0; int z_index = 0; bool z_relative = true; @@ -65,51 +65,51 @@ public: virtual void _edit_set_scale(const Size2 &p_scale) override; virtual Size2 _edit_get_scale() const override; - virtual void _edit_set_rotation(float p_rotation) override; - virtual float _edit_get_rotation() const override; + virtual void _edit_set_rotation(real_t p_rotation) override; + virtual real_t _edit_get_rotation() const override; virtual bool _edit_use_rotation() const override; virtual void _edit_set_rect(const Rect2 &p_edit_rect) override; #endif void set_position(const Point2 &p_pos); - void set_rotation(float p_radians); - void set_rotation_degrees(float p_degrees); - void set_skew(float p_radians); - void set_skew_degrees(float p_radians); + void set_rotation(real_t p_radians); + void set_rotation_degrees(real_t p_degrees); + void set_skew(real_t p_radians); + void set_skew_degrees(real_t p_radians); void set_scale(const Size2 &p_scale); - void rotate(float p_radians); - void move_x(float p_delta, bool p_scaled = false); - void move_y(float p_delta, bool p_scaled = false); + void rotate(real_t p_radians); + void move_x(real_t p_delta, bool p_scaled = false); + void move_y(real_t p_delta, bool p_scaled = false); void translate(const Vector2 &p_amount); void global_translate(const Vector2 &p_amount); void apply_scale(const Size2 &p_amount); Point2 get_position() const; - float get_rotation() const; - float get_skew() const; - float get_rotation_degrees() const; - float get_skew_degrees() const; + real_t get_rotation() const; + real_t get_skew() const; + real_t get_rotation_degrees() const; + real_t get_skew_degrees() const; Size2 get_scale() const; Point2 get_global_position() const; - float get_global_rotation() const; - float get_global_rotation_degrees() const; + real_t get_global_rotation() const; + real_t get_global_rotation_degrees() const; Size2 get_global_scale() const; void set_transform(const Transform2D &p_transform); void set_global_transform(const Transform2D &p_transform); void set_global_position(const Point2 &p_pos); - void set_global_rotation(float p_radians); - void set_global_rotation_degrees(float p_degrees); + void set_global_rotation(real_t p_radians); + void set_global_rotation_degrees(real_t p_degrees); void set_global_scale(const Size2 &p_scale); void set_z_index(int p_z); int get_z_index() const; void look_at(const Vector2 &p_pos); - float get_angle_to(const Vector2 &p_pos) const; + real_t get_angle_to(const Vector2 &p_pos) const; Point2 to_local(Point2 p_global) const; Point2 to_global(Point2 p_local) const; diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 8c9432f2fa..4870ae614b 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,11 +51,11 @@ void ParallaxBackground::_camera_moved(const Transform2D &p_transform, const Poi set_scroll_offset(p_transform.get_origin()); } -void ParallaxBackground::set_scroll_scale(float p_scale) { +void ParallaxBackground::set_scroll_scale(real_t p_scale) { scale = p_scale; } -float ParallaxBackground::get_scroll_scale() const { +real_t ParallaxBackground::get_scroll_scale() const { return scale; } @@ -185,9 +185,5 @@ void ParallaxBackground::_bind_methods() { } ParallaxBackground::ParallaxBackground() { - scale = 1.0; set_layer(-100); //behind all by default - - base_scale = Vector2(1, 1); - ignore_camera_zoom = false; } diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h index 1667880ddb..27134dab29 100644 --- a/scene/2d/parallax_background.h +++ b/scene/2d/parallax_background.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,15 +39,15 @@ class ParallaxBackground : public CanvasLayer { GDCLASS(ParallaxBackground, CanvasLayer); Point2 offset; - float scale; + real_t scale = 1.0; Point2 base_offset; - Point2 base_scale; + Point2 base_scale = Vector2(1, 1); Point2 screen_offset; String group_name; Point2 limit_begin; Point2 limit_end; Point2 final_offset; - bool ignore_camera_zoom; + bool ignore_camera_zoom = false; void _update_scroll(); @@ -61,8 +61,8 @@ public: void set_scroll_offset(const Point2 &p_ofs); Point2 get_scroll_offset() const; - void set_scroll_scale(float p_scale); - float get_scroll_scale() const; + void set_scroll_scale(real_t p_scale); + real_t get_scroll_scale() const; void set_scroll_base_offset(const Point2 &p_ofs); Point2 get_scroll_base_offset() const; diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 01aa5838b4..725e858a43 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,7 +39,7 @@ void ParallaxLayer::set_motion_scale(const Size2 &p_scale) { ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent()); if (pb && is_inside_tree()) { Vector2 ofs = pb->get_final_offset(); - float scale = pb->get_scroll_scale(); + real_t scale = pb->get_scroll_scale(); set_base_offset_and_scale(ofs, scale, screen_offset); } } @@ -54,7 +54,7 @@ void ParallaxLayer::set_motion_offset(const Size2 &p_offset) { ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent()); if (pb && is_inside_tree()) { Vector2 ofs = pb->get_final_offset(); - float scale = pb->get_scroll_scale(); + real_t scale = pb->get_scroll_scale(); set_base_offset_and_scale(ofs, scale, screen_offset); } } @@ -107,7 +107,7 @@ void ParallaxLayer::_notification(int p_what) { } } -void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset) { +void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset) { screen_offset = p_screen_offset; if (!is_inside_tree()) { @@ -139,7 +139,7 @@ String ParallaxLayer::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!Object::cast_to<ParallaxBackground>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node."); @@ -163,5 +163,4 @@ void ParallaxLayer::_bind_methods() { } ParallaxLayer::ParallaxLayer() { - motion_scale = Size2(1, 1); } diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h index 788df19a75..e826e6da9c 100644 --- a/scene/2d/parallax_layer.h +++ b/scene/2d/parallax_layer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,7 +38,7 @@ class ParallaxLayer : public Node2D { Point2 orig_offset; Point2 orig_scale; - Size2 motion_scale; + Size2 motion_scale = Size2(1, 1); Vector2 motion_offset; Vector2 mirroring; void _update_mirroring(); @@ -59,7 +59,7 @@ public: void set_mirroring(const Size2 &p_mirroring); Size2 get_mirroring() const; - void set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset); + void set_base_offset_and_scale(const Point2 &p_offset, real_t p_scale, const Point2 &p_screen_offset); virtual String get_configuration_warning() const override; ParallaxLayer(); diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index 6571474c9b..be160ee1dd 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -96,9 +96,9 @@ void Path2D::_notification(int p_what) { } #ifdef TOOLS_ENABLED - const float line_width = 2 * EDSCALE; + const real_t line_width = 2 * EDSCALE; #else - const float line_width = 2; + const real_t line_width = 2; #endif const Color color = Color(0.5, 0.6, 1.0, 0.7); @@ -164,14 +164,14 @@ void PathFollow2D::_update_transform() { return; } - float path_length = c->get_baked_length(); + real_t path_length = c->get_baked_length(); if (path_length == 0) { return; } Vector2 pos = c->interpolate_baked(offset, cubic); if (rotates) { - float ahead = offset + lookahead; + real_t ahead = offset + lookahead; if (loop && ahead >= path_length) { // If our lookahead will loop, we need to check if the path is closed. @@ -200,7 +200,7 @@ void PathFollow2D::_update_transform() { tangent_to_curve = (ahead_pos - pos).normalized(); } - Vector2 normal_of_curve = -tangent_to_curve.tangent(); + Vector2 normal_of_curve = -tangent_to_curve.orthogonal(); pos += tangent_to_curve * h_offset; pos += normal_of_curve * v_offset; @@ -240,7 +240,7 @@ bool PathFollow2D::get_cubic_interpolation() const { void PathFollow2D::_validate_property(PropertyInfo &property) const { if (property.name == "offset") { - float max = 10000; + real_t max = 10000.0; if (path && path->get_curve().is_valid()) { max = path->get_curve()->get_baked_length(); } @@ -257,7 +257,7 @@ String PathFollow2D::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (!Object::cast_to<Path2D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("PathFollow2D only works when set as a child of a Path2D node."); @@ -301,11 +301,11 @@ void PathFollow2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead"); } -void PathFollow2D::set_offset(float p_offset) { +void PathFollow2D::set_offset(real_t p_offset) { offset = p_offset; if (path) { if (path->get_curve().is_valid()) { - float path_length = path->get_curve()->get_baked_length(); + real_t path_length = path->get_curve()->get_baked_length(); if (loop) { offset = Math::fposmod(offset, path_length); @@ -319,43 +319,41 @@ void PathFollow2D::set_offset(float p_offset) { _update_transform(); } - _change_notify("offset"); - _change_notify("unit_offset"); } -void PathFollow2D::set_h_offset(float p_h_offset) { +void PathFollow2D::set_h_offset(real_t p_h_offset) { h_offset = p_h_offset; if (path) { _update_transform(); } } -float PathFollow2D::get_h_offset() const { +real_t PathFollow2D::get_h_offset() const { return h_offset; } -void PathFollow2D::set_v_offset(float p_v_offset) { +void PathFollow2D::set_v_offset(real_t p_v_offset) { v_offset = p_v_offset; if (path) { _update_transform(); } } -float PathFollow2D::get_v_offset() const { +real_t PathFollow2D::get_v_offset() const { return v_offset; } -float PathFollow2D::get_offset() const { +real_t PathFollow2D::get_offset() const { return offset; } -void PathFollow2D::set_unit_offset(float p_unit_offset) { +void PathFollow2D::set_unit_offset(real_t p_unit_offset) { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { set_offset(p_unit_offset * path->get_curve()->get_baked_length()); } } -float PathFollow2D::get_unit_offset() const { +real_t PathFollow2D::get_unit_offset() const { if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) { return get_offset() / path->get_curve()->get_baked_length(); } else { @@ -363,11 +361,11 @@ float PathFollow2D::get_unit_offset() const { } } -void PathFollow2D::set_lookahead(float p_lookahead) { +void PathFollow2D::set_lookahead(real_t p_lookahead) { lookahead = p_lookahead; } -float PathFollow2D::get_lookahead() const { +real_t PathFollow2D::get_lookahead() const { return lookahead; } diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h index 40042a04ef..671ab493c3 100644 --- a/scene/2d/path_2d.h +++ b/scene/2d/path_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -64,10 +64,10 @@ class PathFollow2D : public Node2D { public: private: Path2D *path = nullptr; - real_t offset = 0; - real_t h_offset = 0; - real_t v_offset = 0; - real_t lookahead = 4; + real_t offset = 0.0; + real_t h_offset = 0.0; + real_t v_offset = 0.0; + real_t lookahead = 4.0; bool cubic = true; bool loop = true; bool rotates = true; @@ -81,20 +81,20 @@ protected: static void _bind_methods(); public: - void set_offset(float p_offset); - float get_offset() const; + void set_offset(real_t p_offset); + real_t get_offset() const; - void set_h_offset(float p_h_offset); - float get_h_offset() const; + void set_h_offset(real_t p_h_offset); + real_t get_h_offset() const; - void set_v_offset(float p_v_offset); - float get_v_offset() const; + void set_v_offset(real_t p_v_offset); + real_t get_v_offset() const; - void set_unit_offset(float p_unit_offset); - float get_unit_offset() const; + void set_unit_offset(real_t p_unit_offset); + real_t get_unit_offset() const; - void set_lookahead(float p_lookahead); - float get_lookahead() const; + void set_lookahead(real_t p_lookahead); + real_t get_lookahead() const; void set_loop(bool p_loop); bool has_loop() const; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index e314669fb0..a615d96687 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -111,8 +111,6 @@ bool PhysicsBody2D::get_collision_layer_bit(int p_bit) const { PhysicsBody2D::PhysicsBody2D(PhysicsServer2D::BodyMode p_mode) : CollisionObject2D(PhysicsServer2D::get_singleton()->body_create(), false) { PhysicsServer2D::get_singleton()->body_set_mode(get_rid(), p_mode); - collision_layer = 1; - collision_mask = 1; set_pickable(false); } @@ -197,7 +195,6 @@ void StaticBody2D::_bind_methods() { StaticBody2D::StaticBody2D() : PhysicsBody2D(PhysicsServer2D::BODY_MODE_STATIC) { - constant_angular_velocity = 0; } StaticBody2D::~StaticBody2D() { @@ -301,7 +298,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap bool in_scene = E->get().in_scene; - if (E->get().shapes.empty()) { + if (E->get().shapes.is_empty()) { if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody2D::_body_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody2D::_body_exit_tree)); @@ -320,11 +317,11 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap struct _RigidBody2DInOut { ObjectID id; - int shape; - int local_shape; + int shape = 0; + int local_shape = 0; }; -bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) { +bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result) { PhysicsServer2D::MotionResult *r = nullptr; if (p_result.is_valid()) { r = p_result->get_result_ptr(); @@ -414,13 +411,13 @@ void RigidBody2D::_direct_state_changed(Object *p_state) { } } - //process remotions + //process removals for (int i = 0; i < toremove_count; i++) { _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); } - //process aditions + //process additions for (int i = 0; i < toadd_count; i++) { _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape); @@ -611,7 +608,7 @@ void RigidBody2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_posit PhysicsServer2D::get_singleton()->body_apply_impulse(get_rid(), p_impulse, p_position); } -void RigidBody2D::apply_torque_impulse(float p_torque) { +void RigidBody2D::apply_torque_impulse(real_t p_torque) { PhysicsServer2D::get_singleton()->body_apply_torque_impulse(get_rid(), p_torque); } @@ -623,11 +620,11 @@ Vector2 RigidBody2D::get_applied_force() const { return PhysicsServer2D::get_singleton()->body_get_applied_force(get_rid()); }; -void RigidBody2D::set_applied_torque(const float p_torque) { +void RigidBody2D::set_applied_torque(const real_t p_torque) { PhysicsServer2D::get_singleton()->body_set_applied_torque(get_rid(), p_torque); }; -float RigidBody2D::get_applied_torque() const { +real_t RigidBody2D::get_applied_torque() const { return PhysicsServer2D::get_singleton()->body_get_applied_torque(get_rid()); }; @@ -639,7 +636,7 @@ void RigidBody2D::add_force(const Vector2 &p_force, const Vector2 &p_position) { PhysicsServer2D::get_singleton()->body_add_force(get_rid(), p_force, p_position); } -void RigidBody2D::add_torque(const float p_torque) { +void RigidBody2D::add_torque(const real_t p_torque) { PhysicsServer2D::get_singleton()->body_add_torque(get_rid(), p_torque); } @@ -724,7 +721,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.empty()) { + if (!warning.is_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."); @@ -841,25 +838,6 @@ void RigidBody2D::_bind_methods() { RigidBody2D::RigidBody2D() : PhysicsBody2D(PhysicsServer2D::BODY_MODE_RIGID) { - mode = MODE_RIGID; - - mass = 1; - - gravity_scale = 1; - linear_damp = -1; - angular_damp = -1; - - max_contacts_reported = 0; - state = nullptr; - - angular_velocity = 0; - sleeping = false; - ccd_mode = CCD_MODE_DISABLED; - - custom_integrator = false; - contact_monitor = nullptr; - can_sleep = true; - PhysicsServer2D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } @@ -906,7 +884,7 @@ bool KinematicBody2D::separate_raycast_shapes(bool p_infinite_inertia, Collision Vector2 recover; int hits = PhysicsServer2D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); int deepest = -1; - float deepest_depth; + real_t deepest_depth; for (int i = 0; i < hits; i++) { if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { deepest = i; @@ -966,7 +944,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_ //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { Vector2 body_velocity = p_linear_velocity; Vector2 body_velocity_normal = body_velocity.normalized(); Vector2 up_direction = p_up_direction.normalized(); @@ -1057,7 +1035,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const return body_velocity; } -Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector2 KinematicBody2D::move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { Vector2 up_direction = p_up_direction.normalized(); bool was_on_floor = on_floor; @@ -1123,11 +1101,11 @@ bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_moti return PhysicsServer2D::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin); } -void KinematicBody2D::set_safe_margin(float p_margin) { +void KinematicBody2D::set_safe_margin(real_t p_margin) { margin = p_margin; } -float KinematicBody2D::get_safe_margin() const { +real_t KinematicBody2D::get_safe_margin() const { return margin; } @@ -1219,8 +1197,8 @@ void KinematicBody2D::_notification(int p_what) { void KinematicBody2D::_bind_methods() { ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody2D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody2D::move_and_slide_with_snap, DEFVAL(Vector2(0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move, DEFVAL(true)); diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 294b57eb13..2dc853b23b 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,8 +41,8 @@ class KinematicCollision2D; class PhysicsBody2D : public CollisionObject2D { GDCLASS(PhysicsBody2D, CollisionObject2D); - uint32_t collision_layer; - uint32_t collision_mask; + uint32_t collision_layer = 1; + uint32_t collision_mask = 1; protected: void _notification(int p_what); @@ -74,7 +74,7 @@ class StaticBody2D : public PhysicsBody2D { GDCLASS(StaticBody2D, PhysicsBody2D); Vector2 constant_linear_velocity; - real_t constant_angular_velocity; + real_t constant_angular_velocity = 0.0; Ref<PhysicsMaterial> physics_material_override; @@ -116,30 +116,30 @@ public: }; private: - bool can_sleep; - PhysicsDirectBodyState2D *state; - Mode mode; + bool can_sleep = true; + PhysicsDirectBodyState2D *state = nullptr; + Mode mode = MODE_RIGID; - real_t mass; + real_t mass = 1.0; Ref<PhysicsMaterial> physics_material_override; - real_t gravity_scale; - real_t linear_damp; - real_t angular_damp; + real_t gravity_scale = 1.0; + real_t linear_damp = -1.0; + real_t angular_damp = -1.0; Vector2 linear_velocity; - real_t angular_velocity; - bool sleeping; + real_t angular_velocity = 0.0; + bool sleeping = false; - int max_contacts_reported; + int max_contacts_reported = 0; - bool custom_integrator; + bool custom_integrator = false; - CCDMode ccd_mode; + CCDMode ccd_mode = CCD_MODE_DISABLED; struct ShapePair { - int body_shape; - int local_shape; - bool tagged; + int body_shape = 0; + int local_shape = 0; + bool tagged = false; bool operator<(const ShapePair &p_sp) const { if (body_shape == p_sp.body_shape) { return local_shape < p_sp.local_shape; @@ -160,23 +160,23 @@ private: }; struct BodyState { //int rc; - bool in_scene; + bool in_scene = false; VSet<ShapePair> shapes; }; struct ContactMonitor { - bool locked; + bool locked = false; Map<ObjectID, BodyState> body_map; }; - ContactMonitor *contact_monitor; + ContactMonitor *contact_monitor = nullptr; void _body_enter_tree(ObjectID p_id); void _body_exit_tree(ObjectID p_id); void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape); void _direct_state_changed(Object *p_state); - bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, float p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); + bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); protected: void _notification(int p_what); @@ -232,17 +232,17 @@ public: void apply_central_impulse(const Vector2 &p_impulse); void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()); - void apply_torque_impulse(float p_torque); + void apply_torque_impulse(real_t p_torque); void set_applied_force(const Vector2 &p_force); Vector2 get_applied_force() const; - void set_applied_torque(const float p_torque); - float get_applied_torque() const; + void set_applied_torque(const real_t p_torque); + real_t get_applied_torque() const; void add_central_force(const Vector2 &p_force); void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()); - void add_torque(float p_torque); + void add_torque(real_t p_torque); TypedArray<Node2D> get_colliding_bodies() const; //function for script @@ -268,15 +268,15 @@ public: Vector2 collider_vel; ObjectID collider; RID collider_rid; - int collider_shape; + int collider_shape = 0; Variant collider_metadata; Vector2 remainder; Vector2 travel; - int local_shape; + int local_shape = 0; }; private: - float margin; + real_t margin; Vector2 floor_normal; Vector2 floor_velocity; @@ -309,11 +309,11 @@ public: bool separate_raycast_shapes(bool p_infinite_inertia, Collision &r_collision); - void set_safe_margin(float p_margin); - float get_safe_margin() const; + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; - Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); - Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); + Vector2 move_and_slide_with_snap(const Vector2 &p_linear_velocity, const Vector2 &p_snap, const Vector2 &p_up_direction = Vector2(0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 26340bb861..1a7038bb80 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -90,6 +90,12 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler } #endif +void Polygon2D::_validate_property(PropertyInfo &property) const { + if (!invert && property.name == "invert_border") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void Polygon2D::_skeleton_bone_setup_changed() { update(); } @@ -154,8 +160,8 @@ void Polygon2D::_notification(int p_what) { if (invert) { Rect2 bounds; int highest_idx = -1; - float highest_y = -1e20; - float sum = 0; + real_t highest_y = -1e20; + real_t sum = 0.0; for (int i = 0; i < len; i++) { if (i == 0) { @@ -273,7 +279,7 @@ void Polygon2D::_notification(int p_what) { //normalize the weights for (int i = 0; i < vc; i++) { - float tw = 0; + real_t tw = 0.0; for (int j = 0; j < 4; j++) { tw += weightsw[i * 4 + j]; } @@ -426,20 +432,20 @@ Vector2 Polygon2D::get_texture_offset() const { return tex_ofs; } -void Polygon2D::set_texture_rotation(float p_rot) { +void Polygon2D::set_texture_rotation(real_t p_rot) { tex_rot = p_rot; update(); } -float Polygon2D::get_texture_rotation() const { +real_t Polygon2D::get_texture_rotation() const { return tex_rot; } -void Polygon2D::set_texture_rotation_degrees(float p_rot) { +void Polygon2D::set_texture_rotation_degrees(real_t p_rot) { set_texture_rotation(Math::deg2rad(p_rot)); } -float Polygon2D::get_texture_rotation_degrees() const { +real_t Polygon2D::get_texture_rotation_degrees() const { return Math::rad2deg(get_texture_rotation()); } @@ -455,6 +461,7 @@ Size2 Polygon2D::get_texture_scale() const { void Polygon2D::set_invert(bool p_invert) { invert = p_invert; update(); + notify_property_list_changed(); } bool Polygon2D::get_invert() const { @@ -470,12 +477,12 @@ bool Polygon2D::get_antialiased() const { return antialiased; } -void Polygon2D::set_invert_border(float p_invert_border) { +void Polygon2D::set_invert_border(real_t p_invert_border) { invert_border = p_invert_border; update(); } -float Polygon2D::get_invert_border() const { +real_t Polygon2D::get_invert_border() const { return invert_border; } @@ -483,7 +490,6 @@ void Polygon2D::set_offset(const Vector2 &p_offset) { offset = p_offset; rect_cache_dirty = true; update(); - _change_notify("offset"); } Vector2 Polygon2D::get_offset() const { @@ -649,13 +655,4 @@ void Polygon2D::_bind_methods() { } Polygon2D::Polygon2D() { - invert = false; - invert_border = 100; - antialiased = false; - tex_rot = 0; - tex_tile = true; - tex_scale = Vector2(1, 1); - color = Color(1, 1, 1); - rect_cache_dirty = true; - internal_vertices = 0; } diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index e2a8db414a..c207024a53 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,7 +40,7 @@ class Polygon2D : public Node2D { Vector<Vector2> uv; Vector<Color> vertex_colors; Array polygons; - int internal_vertices; + int internal_vertices = 0; struct Bone { NodePath path; @@ -49,19 +49,19 @@ class Polygon2D : public Node2D { Vector<Bone> bone_weights; - Color color; + Color color = Color(1, 1, 1); Ref<Texture2D> texture; - Size2 tex_scale; + Size2 tex_scale = Vector2(1, 1); Vector2 tex_ofs; - bool tex_tile; - float tex_rot; - bool invert; - float invert_border; - bool antialiased; + bool tex_tile = true; + real_t tex_rot = 0.0; + bool invert = false; + real_t invert_border = 100.0; + bool antialiased = false; Vector2 offset; - mutable bool rect_cache_dirty; + mutable bool rect_cache_dirty = true; mutable Rect2 item_rect; NodePath skeleton; @@ -75,6 +75,7 @@ class Polygon2D : public Node2D { protected: void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: #ifdef TOOLS_ENABLED @@ -114,11 +115,11 @@ public: void set_texture_offset(const Vector2 &p_offset); Vector2 get_texture_offset() const; - void set_texture_rotation(float p_rot); - float get_texture_rotation() const; + void set_texture_rotation(real_t p_rot); + real_t get_texture_rotation() const; - void set_texture_rotation_degrees(float p_rot); - float get_texture_rotation_degrees() const; + void set_texture_rotation_degrees(real_t p_rot); + real_t get_texture_rotation_degrees() const; void set_texture_scale(const Size2 &p_scale); Size2 get_texture_scale() const; @@ -129,8 +130,8 @@ public: void set_antialiased(bool p_antialiased); bool get_antialiased() const; - void set_invert_border(float p_invert_border); - float get_invert_border() const; + void set_invert_border(real_t p_invert_border); + real_t get_invert_border() const; void set_offset(const Vector2 &p_offset); Vector2 get_offset() const; diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index 8e4165cf50..5c7d65e3e0 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,10 +33,10 @@ #include "core/config/engine.h" #include "scene/resources/texture.h" -const float DEFAULT_GIZMO_EXTENTS = 10.0; +const real_t DEFAULT_GIZMO_EXTENTS = 10.0; void Position2D::_draw_cross() { - float extents = get_gizmo_extents(); + real_t extents = get_gizmo_extents(); // Colors taken from `axis_x_color` and `axis_y_color` (defined in `editor/editor_themes.cpp`) draw_line(Point2(-extents, 0), Point2(+extents, 0), Color(0.96, 0.20, 0.32)); draw_line(Point2(0, -extents), Point2(0, +extents), Color(0.53, 0.84, 0.01)); @@ -44,7 +44,7 @@ void Position2D::_draw_cross() { #ifdef TOOLS_ENABLED Rect2 Position2D::_edit_get_rect() const { - float extents = get_gizmo_extents(); + real_t extents = get_gizmo_extents(); return Rect2(Point2(-extents, -extents), Size2(extents * 2, extents * 2)); } @@ -70,7 +70,7 @@ void Position2D::_notification(int p_what) { } } -void Position2D::set_gizmo_extents(float p_extents) { +void Position2D::set_gizmo_extents(real_t p_extents) { if (p_extents == DEFAULT_GIZMO_EXTENTS) { set_meta("_gizmo_extents_", Variant()); } else { @@ -80,7 +80,7 @@ void Position2D::set_gizmo_extents(float p_extents) { update(); } -float Position2D::get_gizmo_extents() const { +real_t Position2D::get_gizmo_extents() const { if (has_meta("_gizmo_extents_")) { return get_meta("_gizmo_extents_"); } else { diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h index 01b380bca8..9ed622c8f6 100644 --- a/scene/2d/position_2d.h +++ b/scene/2d/position_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,8 +48,8 @@ public: virtual bool _edit_use_rect() const override; #endif - void set_gizmo_extents(float p_extents); - float get_gizmo_extents() const; + void set_gizmo_extents(real_t p_extents); + real_t get_gizmo_extents() const; Position2D(); }; diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index e53f89c46d..50625a0f39 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -159,30 +159,7 @@ void RayCast2D::_notification(int p_what) { if (!Engine::get_singleton()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { break; } - Transform2D xf; - 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(); - if (!enabled) { - float g = draw_col.get_v(); - draw_col.r = g; - draw_col.g = g; - draw_col.b = g; - } - draw_line(Vector2(), target_position, draw_col, 2); - Vector<Vector2> pts; - float tsize = 8; - pts.push_back(xf.xform(Vector2(tsize, 0))); - pts.push_back(xf.xform(Vector2(0, Math_SQRT12 * tsize))); - pts.push_back(xf.xform(Vector2(0, -Math_SQRT12 * tsize))); - Vector<Color> cols; - for (int i = 0; i < 3; i++) { - cols.push_back(draw_col); - } - - draw_primitive(pts, cols, Vector<Vector2>()); + _draw_debug_shape(); } break; @@ -212,7 +189,7 @@ void RayCast2D::_update_raycast_state() { } PhysicsDirectSpaceState2D::RayResult rr; - + bool prev_collision_state = collided; if (dss->intersect_ray(gt.get_origin(), gt.xform(to), rr, exclude, collision_mask, collide_with_bodies, collide_with_areas)) { collided = true; against = rr.collider_id; @@ -224,6 +201,48 @@ void RayCast2D::_update_raycast_state() { against = ObjectID(); against_shape = 0; } + + if (prev_collision_state != collided) { + update(); + } +} + +void RayCast2D::_draw_debug_shape() { + Color draw_col = collided ? Color(1.0, 0.01, 0) : get_tree()->get_debug_collisions_color(); + if (!enabled) { + float g = draw_col.get_v(); + draw_col.r = g; + draw_col.g = g; + draw_col.b = g; + } + + // Draw an arrow indicating where the RayCast is pointing to + const float max_arrow_size = 6; + const float line_width = 1.4; + bool no_line = target_position.length() < line_width; + float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); + + if (no_line) { + arrow_size = target_position.length(); + } else { + draw_line(Vector2(), target_position - target_position.normalized() * arrow_size, draw_col, line_width); + } + + Transform2D xf; + xf.rotate(target_position.angle()); + xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); + + Vector<Vector2> pts; + pts.push_back(xf.xform(Vector2(arrow_size, 0))); + pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size))); + pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size))); + + Vector<Color> cols; + for (int i = 0; i < 3; i++) { + cols.push_back(draw_col); + } + + draw_primitive(pts, cols, Vector<Vector2>()); } void RayCast2D::force_raycast_update() { @@ -325,12 +344,4 @@ void RayCast2D::_bind_methods() { } RayCast2D::RayCast2D() { - enabled = true; - collided = false; - against_shape = 0; - collision_mask = 1; - 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 14932f782b..984c6bda49 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,20 +36,22 @@ class RayCast2D : public Node2D { GDCLASS(RayCast2D, Node2D); - bool enabled; - bool collided; + bool enabled = true; + bool collided = false; ObjectID against; - int against_shape; + int against_shape = 0; Vector2 collision_point; Vector2 collision_normal; Set<RID> exclude; - uint32_t collision_mask; - bool exclude_parent_body; + uint32_t collision_mask = 1; + bool exclude_parent_body = true; - Vector2 target_position; + Vector2 target_position = Vector2(0, 50); - bool collide_with_areas; - bool collide_with_bodies; + bool collide_with_areas = false; + bool collide_with_bodies = true; + + void _draw_debug_shape(); protected: void _notification(int p_what); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index 7655416ce2..f10714e28a 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -189,7 +189,7 @@ 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))) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("Path property must point to a valid Node2D node to work."); @@ -223,10 +223,5 @@ void RemoteTransform2D::_bind_methods() { } RemoteTransform2D::RemoteTransform2D() { - use_global_coordinates = true; - update_remote_position = true; - update_remote_rotation = true; - update_remote_scale = true; - set_notify_transform(true); } diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index 8b6f8d9678..4a26d7b339 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,10 +40,10 @@ class RemoteTransform2D : public Node2D { ObjectID cache; - bool use_global_coordinates; - bool update_remote_position; - bool update_remote_rotation; - bool update_remote_scale; + bool use_global_coordinates = true; + bool update_remote_position = true; + bool update_remote_rotation = true; + bool update_remote_scale = true; void _update_remote(); void _update_cache(); diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp index ea1d9f5930..2d19d254b1 100644 --- a/scene/2d/skeleton_2d.cpp +++ b/scene/2d/skeleton_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -119,11 +119,11 @@ void Bone2D::apply_rest() { set_transform(rest); } -void Bone2D::set_default_length(float p_length) { +void Bone2D::set_default_length(real_t p_length) { default_length = p_length; } -float Bone2D::get_default_length() const { +real_t Bone2D::get_default_length() const { return default_length; } @@ -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.empty()) { + if (!warning.is_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.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one."); @@ -157,10 +157,6 @@ String Bone2D::get_configuration_warning() const { } Bone2D::Bone2D() { - skeleton = nullptr; - parent_bone = nullptr; - skeleton_index = -1; - default_length = 16; set_notify_local_transform(true); //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error. for (int i = 0; i < 3; i++) { @@ -186,9 +182,9 @@ void Skeleton2D::_update_bone_setup() { } bone_setup_dirty = false; - RS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true); + RS::get_singleton()->skeleton_allocate_data(skeleton, bones.size(), true); - bones.sort(); //sorty so they are always in the same order/index + bones.sort(); //sorting so that they are always in the same order/index for (int i = 0; i < bones.size(); i++) { bones.write[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose @@ -293,9 +289,6 @@ void Skeleton2D::_bind_methods() { } Skeleton2D::Skeleton2D() { - bone_setup_dirty = true; - transform_dirty = true; - skeleton = RS::get_singleton()->skeleton_create(); set_notify_transform(true); } diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h index 7e9ffd98e6..1f43ea742b 100644 --- a/scene/2d/skeleton_2d.h +++ b/scene/2d/skeleton_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,12 +43,12 @@ class Bone2D : public Node2D { friend class AnimatedValuesBackup; #endif - Bone2D *parent_bone; - Skeleton2D *skeleton; + Bone2D *parent_bone = nullptr; + Skeleton2D *skeleton = nullptr; Transform2D rest; - float default_length; + real_t default_length = 16.0; - int skeleton_index; + int skeleton_index = -1; protected: void _notification(int p_what); @@ -62,8 +62,8 @@ public: String get_configuration_warning() const override; - void set_default_length(float p_length); - float get_default_length() const; + void set_default_length(real_t p_length); + real_t get_default_length() const; int get_index_in_skeleton() const; @@ -82,19 +82,19 @@ class Skeleton2D : public Node2D { bool operator<(const Bone &p_bone) const { return p_bone.bone->is_greater_than(bone); } - Bone2D *bone; - int parent_index; + Bone2D *bone = nullptr; + int parent_index = 0; Transform2D accum_transform; Transform2D rest_inverse; }; Vector<Bone> bones; - bool bone_setup_dirty; + bool bone_setup_dirty = true; void _make_bone_setup_dirty(); void _update_bone_setup(); - bool transform_dirty; + bool transform_dirty = true; void _make_transform_dirty(); void _update_transform(); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index a065565a0f..7c93edbff9 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -77,14 +77,14 @@ Rect2 Sprite2D::get_anchorable_rect() const { return get_rect(); } -void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const { +void Sprite2D::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const { Rect2 base_rect; - if (region) { - r_filter_clip = region_filter_clip; + if (region_enabled) { + r_filter_clip_enabled = region_filter_clip_enabled; base_rect = region_rect; } else { - r_filter_clip = false; + r_filter_clip_enabled = false; base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); } @@ -129,10 +129,10 @@ void Sprite2D::_notification(int p_what) { */ Rect2 src_rect, dst_rect; - bool filter_clip; - _get_rects(src_rect, dst_rect, filter_clip); + bool filter_clip_enabled; + _get_rects(src_rect, dst_rect, filter_clip_enabled); - texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip); + texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, filter_clip_enabled); } break; } } @@ -155,7 +155,6 @@ void Sprite2D::set_texture(const Ref<Texture2D> &p_texture) { update(); emit_signal("texture_changed"); item_rect_changed(); - _change_notify("texture"); } Ref<Texture2D> Sprite2D::get_texture() const { @@ -176,7 +175,6 @@ void Sprite2D::set_offset(const Point2 &p_offset) { offset = p_offset; update(); item_rect_changed(); - _change_notify("offset"); } Point2 Sprite2D::get_offset() const { @@ -201,17 +199,18 @@ bool Sprite2D::is_flipped_v() const { return vflip; } -void Sprite2D::set_region(bool p_region) { - if (p_region == region) { +void Sprite2D::set_region_enabled(bool p_region_enabled) { + if (p_region_enabled == region_enabled) { return; } - region = p_region; + region_enabled = p_region_enabled; update(); + notify_property_list_changed(); } -bool Sprite2D::is_region() const { - return region; +bool Sprite2D::is_region_enabled() const { + return region_enabled; } void Sprite2D::set_region_rect(const Rect2 &p_region_rect) { @@ -221,24 +220,22 @@ void Sprite2D::set_region_rect(const Rect2 &p_region_rect) { region_rect = p_region_rect; - if (region) { + if (region_enabled) { item_rect_changed(); } - - _change_notify("region_rect"); } Rect2 Sprite2D::get_region_rect() const { return region_rect; } -void Sprite2D::set_region_filter_clip(bool p_enable) { - region_filter_clip = p_enable; +void Sprite2D::set_region_filter_clip_enabled(bool p_region_filter_clip_enabled) { + region_filter_clip_enabled = p_region_filter_clip_enabled; update(); } bool Sprite2D::is_region_filter_clip_enabled() const { - return region_filter_clip; + return region_filter_clip_enabled; } void Sprite2D::set_frame(int p_frame) { @@ -250,8 +247,6 @@ void Sprite2D::set_frame(int p_frame) { frame = p_frame; - _change_notify("frame"); - _change_notify("frame_coords"); emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -275,7 +270,7 @@ void Sprite2D::set_vframes(int p_amount) { vframes = p_amount; update(); item_rect_changed(); - _change_notify(); + notify_property_list_changed(); } int Sprite2D::get_vframes() const { @@ -287,7 +282,7 @@ void Sprite2D::set_hframes(int p_amount) { hframes = p_amount; update(); item_rect_changed(); - _change_notify(); + notify_property_list_changed(); } int Sprite2D::get_hframes() const { @@ -304,8 +299,8 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const { } Rect2 src_rect, dst_rect; - bool filter_clip; - _get_rects(src_rect, dst_rect, filter_clip); + bool filter_clip_enabled; + _get_rects(src_rect, dst_rect, filter_clip_enabled); dst_rect.size = dst_rect.size.abs(); if (!dst_rect.has_point(p_point)) { @@ -355,7 +350,7 @@ Rect2 Sprite2D::get_rect() const { Size2i s; - if (region) { + if (region_enabled) { s = region_rect.size; } else { s = texture->get_size(); @@ -389,6 +384,10 @@ void Sprite2D::_validate_property(PropertyInfo &property) const { if (property.name == "frame_coords") { property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } + + if (!region_enabled && (property.name == "region_rect" || property.name == "region_filter_clip")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } } void Sprite2D::_texture_changed() { @@ -415,15 +414,15 @@ void Sprite2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &Sprite2D::set_flip_v); ClassDB::bind_method(D_METHOD("is_flipped_v"), &Sprite2D::is_flipped_v); - ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite2D::set_region); - ClassDB::bind_method(D_METHOD("is_region"), &Sprite2D::is_region); + ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite2D::set_region_enabled); + ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite2D::is_region_enabled); ClassDB::bind_method(D_METHOD("is_pixel_opaque", "pos"), &Sprite2D::is_pixel_opaque); ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite2D::set_region_rect); ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite2D::get_region_rect); - ClassDB::bind_method(D_METHOD("set_region_filter_clip", "enabled"), &Sprite2D::set_region_filter_clip); + ClassDB::bind_method(D_METHOD("set_region_filter_clip_enabled", "enabled"), &Sprite2D::set_region_filter_clip_enabled); ClassDB::bind_method(D_METHOD("is_region_filter_clip_enabled"), &Sprite2D::is_region_filter_clip_enabled); ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite2D::set_frame); @@ -456,22 +455,12 @@ void Sprite2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords"); ADD_GROUP("Region", "region_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip"), "set_region_filter_clip", "is_region_filter_clip_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_filter_clip_enabled"), "set_region_filter_clip_enabled", "is_region_filter_clip_enabled"); } Sprite2D::Sprite2D() { - centered = true; - hflip = false; - vflip = false; - region = false; - region_filter_clip = false; - - frame = 0; - - vframes = 1; - hframes = 1; } Sprite2D::~Sprite2D() { diff --git a/scene/2d/sprite_2d.h b/scene/2d/sprite_2d.h index 2875d333bb..9db74cfe26 100644 --- a/scene/2d/sprite_2d.h +++ b/scene/2d/sprite_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,23 +39,23 @@ class Sprite2D : public Node2D { Ref<Texture2D> texture; Color specular_color; - float shininess; + real_t shininess = 0.0; - bool centered; + bool centered = true; Point2 offset; - bool hflip; - bool vflip; - bool region; + bool hflip = false; + bool vflip = false; + bool region_enabled = false; Rect2 region_rect; - bool region_filter_clip; + bool region_filter_clip_enabled = false; - int frame; + int frame = 0; - int vframes; - int hframes; + int vframes = 1; + int hframes = 1; - void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const; + void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip_enabled) const; void _texture_changed(); @@ -97,10 +97,10 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - void set_region(bool p_region); - bool is_region() const; + void set_region_enabled(bool p_enabled); + bool is_region_enabled() const; - void set_region_filter_clip(bool p_enable); + void set_region_filter_clip_enabled(bool p_enabled); bool is_region_filter_clip_enabled() const; void set_region_rect(const Rect2 &p_region_rect); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index bff191a2bf..81a5b0b28c 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,16 +48,6 @@ int TileMap::_get_quadrant_size() const { void TileMap::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - Node2D *c = this; - while (c) { - navigation = Object::cast_to<Navigation2D>(c); - if (navigation) { - break; - } - - c = Object::cast_to<Node2D>(c->get_parent()); - } - if (use_parent) { _clear_quadrants(); collision_parent = Object::cast_to<CollisionObject2D>(get_parent()); @@ -77,12 +67,10 @@ void TileMap::_notification(int p_what) { _update_quadrant_space(RID()); for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { Quadrant &q = E->get(); - if (navigation) { - for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID()); - } - q.navpoly_ids.clear(); + for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { + NavigationServer2D::get_singleton()->region_set_map(F->get().region, RID()); } + q.navpoly_ids.clear(); if (collision_parent) { collision_parent->remove_shape_owner(q.shape_owner_id); @@ -96,8 +84,6 @@ void TileMap::_notification(int p_what) { } collision_parent = nullptr; - navigation = nullptr; - } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -135,11 +121,6 @@ void TileMap::_update_quadrant_transform() { local_transform = get_transform(); } - Transform2D nav_rel; - if (navigation) { - nav_rel = get_relative_transform_to_parent(navigation); - } - for (Map<PosKey, Quadrant>::Element *E = quadrant_map.front(); E; E = E->next()) { Quadrant &q = E->get(); Transform2D xform; @@ -150,9 +131,9 @@ void TileMap::_update_quadrant_transform() { PhysicsServer2D::get_singleton()->body_set_state(q.body, PhysicsServer2D::BODY_STATE_TRANSFORM, xform); } - if (navigation) { + if (bake_navigation) { for (Map<PosKey, Quadrant::NavPoly>::Element *F = q.navpoly_ids.front(); F; F = F->next()) { - NavigationServer2D::get_singleton()->region_set_transform(F->get().region, nav_rel * F->get().xform); + NavigationServer2D::get_singleton()->region_set_transform(F->get().region, F->get().xform); } } @@ -165,7 +146,6 @@ void TileMap::_update_quadrant_transform() { void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { if (tile_set.is_valid()) { tile_set->disconnect("changed", callable_mp(this, &TileMap::_recreate_quadrants)); - tile_set->remove_change_receptor(this); } _clear_quadrants(); @@ -173,7 +153,6 @@ void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { if (tile_set.is_valid()) { tile_set->connect("changed", callable_mp(this, &TileMap::_recreate_quadrants)); - tile_set->add_change_receptor(this); } else { clear(); } @@ -317,11 +296,6 @@ void TileMap::update_dirty_quadrants() { RenderingServer *vs = RenderingServer::get_singleton(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); Vector2 tofs = get_cell_draw_offset(); - Transform2D nav_rel; - if (navigation) { - nav_rel = get_relative_transform_to_parent(navigation); - } - Vector2 qofs; SceneTree *st = SceneTree::get_singleton(); @@ -354,12 +328,10 @@ void TileMap::update_dirty_quadrants() { } int shape_idx = 0; - if (navigation) { - for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { - NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID()); - } - q.navpoly_ids.clear(); + for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { + NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID()); } + q.navpoly_ids.clear(); for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) { RS::get_singleton()->free(E->get().id); @@ -581,7 +553,7 @@ void TileMap::update_dirty_quadrants() { vs->canvas_item_add_set_transform(debug_canvas_item, Transform2D()); } - if (navigation) { + if (bake_navigation) { Ref<NavigationPolygon> navpoly; Vector2 npoly_ofs; if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE || tile_set->tile_get_tile_mode(c.id) == TileSet::ATLAS_TILE) { @@ -598,8 +570,8 @@ void TileMap::update_dirty_quadrants() { _fix_cell_transform(xform, c, npoly_ofs, s); RID region = NavigationServer2D::get_singleton()->region_create(); - NavigationServer2D::get_singleton()->region_set_map(region, navigation->get_rid()); - NavigationServer2D::get_singleton()->region_set_transform(region, nav_rel * xform); + NavigationServer2D::get_singleton()->region_set_map(region, get_world_2d()->get_navigation_map()); + NavigationServer2D::get_singleton()->region_set_transform(region, xform); NavigationServer2D::get_singleton()->region_set_navpoly(region, navpoly); Quadrant::NavPoly np; @@ -789,12 +761,10 @@ void TileMap::_erase_quadrant(Map<PosKey, Quadrant>::Element *Q) { dirty_quadrant_list.remove(&q.dirty_list); } - if (navigation) { - for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { - NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID()); - } - q.navpoly_ids.clear(); + for (Map<PosKey, Quadrant::NavPoly>::Element *E = q.navpoly_ids.front(); E; E = E->next()) { + NavigationServer2D::get_singleton()->region_set_map(E->get().region, RID()); } + q.navpoly_ids.clear(); for (Map<PosKey, Quadrant::Occluder>::Element *E = q.occluder_instances.front(); E; E = E->next()) { RS::get_singleton()->free(E->get().id); @@ -1024,7 +994,9 @@ void TileMap::update_dirty_bitmask() { void TileMap::fix_invalid_tiles() { ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot fix invalid tiles if Tileset is not open."); - for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) { + + Map<PosKey, Cell> temp_tile_map = tile_map; + for (Map<PosKey, Cell>::Element *E = temp_tile_map.front(); E; E = E->next()) { if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) { set_cell(E->key().x, E->key().y, INVALID_CELL); } @@ -1328,7 +1300,7 @@ void TileMap::set_collision_use_parent(bool p_use_parent) { } _recreate_quadrants(); - _change_notify(); + notify_property_list_changed(); update_configuration_warning(); } @@ -1360,6 +1332,17 @@ float TileMap::get_collision_bounce() const { return bounce; } +void TileMap::set_bake_navigation(bool p_bake_navigation) { + bake_navigation = p_bake_navigation; + for (Map<PosKey, Quadrant>::Element *F = quadrant_map.front(); F; F = F->next()) { + _make_quadrant_dirty(F); + } +} + +bool TileMap::is_baking_navigation() { + return bake_navigation; +} + uint32_t TileMap::get_collision_layer() const { return collision_layer; } @@ -1714,7 +1697,7 @@ String TileMap::get_configuration_warning() const { String warning = Node2D::get_configuration_warning(); if (use_parent && !collision_parent) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } return TTR("TileMap with Use Parent on needs a parent CollisionObject2D to give shapes to. Please use it as a child of Area2D, StaticBody2D, RigidBody2D, KinematicBody2D, etc. to give them a shape."); @@ -1784,6 +1767,9 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collision_bounce", "value"), &TileMap::set_collision_bounce); ClassDB::bind_method(D_METHOD("get_collision_bounce"), &TileMap::get_collision_bounce); + ClassDB::bind_method(D_METHOD("set_bake_navigation", "bake_navigation"), &TileMap::set_bake_navigation); + ClassDB::bind_method(D_METHOD("is_baking_navigation"), &TileMap::is_baking_navigation); + ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &TileMap::set_occluder_light_mask); ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &TileMap::get_occluder_light_mask); @@ -1842,6 +1828,9 @@ void TileMap::_bind_methods() { ADD_GROUP("Occluder", "occluder_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "occluder_light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask"); + ADD_GROUP("Navigation", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_navigation"), "set_bake_navigation", "is_baking_navigation"); + ADD_PROPERTY_DEFAULT("format", FORMAT_1); ADD_SIGNAL(MethodInfo("settings_changed")); @@ -1863,47 +1852,11 @@ void TileMap::_bind_methods() { BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT); } -void TileMap::_changed_callback(Object *p_changed, const char *p_prop) { - if (tile_set.is_valid() && tile_set.ptr() == p_changed) { - emit_signal("settings_changed"); - } -} - TileMap::TileMap() { - rect_cache_dirty = true; - used_size_cache_dirty = true; - pending_update = false; - quadrant_order_dirty = false; - quadrant_size = 16; - cell_size = Size2(64, 64); - custom_transform = Transform2D(64, 0, 0, 64, 0, 0); - collision_layer = 1; - collision_mask = 1; - friction = 1; - bounce = 0; - mode = MODE_SQUARE; - half_offset = HALF_OFFSET_DISABLED; - use_parent = false; - collision_parent = nullptr; - use_kinematic = false; - navigation = nullptr; - use_y_sort = false; - compatibility_mode = false; - centered_textures = false; - occluder_light_mask = 1; - clip_uv = false; - format = FORMAT_1; // Assume lowest possible format if none is present - - fp_adjust = 0.00001; - tile_origin = TILE_ORIGIN_TOP_LEFT; set_notify_transform(true); set_notify_local_transform(false); } TileMap::~TileMap() { - if (tile_set.is_valid()) { - tile_set->remove_change_receptor(this); - } - clear(); } diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 22b615a379..26c84a0bb9 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,7 +33,6 @@ #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" @@ -70,22 +69,22 @@ private: }; Ref<TileSet> tile_set; - Size2i cell_size; - int quadrant_size; - Mode mode; - Transform2D custom_transform; - HalfOffset half_offset; - bool use_parent; - CollisionObject2D *collision_parent; - bool use_kinematic; - Navigation2D *navigation; + Size2i cell_size = Size2(64, 64); + int quadrant_size = 16; + Mode mode = MODE_SQUARE; + Transform2D custom_transform = Transform2D(64, 0, 0, 64, 0, 0); + HalfOffset half_offset = HALF_OFFSET_DISABLED; + bool use_parent = false; + CollisionObject2D *collision_parent = nullptr; + bool use_kinematic = false; + bool bake_navigation = false; union PosKey { struct { int16_t x; int16_t y; }; - uint32_t key; + uint32_t key = 0; //using a more precise comparison so the regions can be sorted later bool operator<(const PosKey &p_k) const { return (y == p_k.y) ? x < p_k.x : y < p_k.y; } @@ -119,8 +118,7 @@ private: int16_t autotile_coord_y : 16; }; - uint64_t _u64t; - Cell() { _u64t = 0; } + uint64_t _u64t = 0; }; Map<PosKey, Cell> tile_map; @@ -130,7 +128,7 @@ private: Vector2 pos; List<RID> canvas_items; RID body; - uint32_t shape_owner_id; + uint32_t shape_owner_id = 0; SelfList<Quadrant> dirty_list; @@ -176,27 +174,27 @@ private: SelfList<Quadrant>::List dirty_quadrant_list; - bool pending_update; + bool pending_update = false; Rect2 rect_cache; - bool rect_cache_dirty; + bool rect_cache_dirty = true; Rect2 used_size_cache; - bool used_size_cache_dirty; - bool quadrant_order_dirty; - bool use_y_sort; - bool compatibility_mode; - bool centered_textures; - bool clip_uv; - float fp_adjust; - float friction; - float bounce; - uint32_t collision_layer; - uint32_t collision_mask; - mutable DataFormat format; - - TileOrigin tile_origin; - - int occluder_light_mask; + bool used_size_cache_dirty = true; + bool quadrant_order_dirty = false; + bool use_y_sort = false; + bool compatibility_mode = false; + bool centered_textures = false; + bool clip_uv = false; + float fp_adjust = 0.00001; + float friction = 1.0; + float bounce = 0.0; + uint32_t collision_layer = 1; + uint32_t collision_mask = 1; + mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present + + TileOrigin tile_origin = TILE_ORIGIN_TOP_LEFT; + + int occluder_light_mask = 1; void _fix_cell_transform(Transform2D &xform, const Cell &p_cell, const Vector2 &p_offset, const Size2 &p_sc); @@ -233,7 +231,6 @@ protected: static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; - virtual void _changed_callback(Object *p_changed, const char *p_prop) override; public: enum { @@ -297,6 +294,9 @@ public: void set_collision_bounce(float p_bounce); float get_collision_bounce() const; + void set_bake_navigation(bool p_bake_navigation); + bool is_baking_navigation(); + void set_mode(Mode p_mode); Mode get_mode() const; diff --git a/scene/2d/touch_screen_button.cpp b/scene/2d/touch_screen_button.cpp index 4597300db8..9d6868a1b2 100644 --- a/scene/2d/touch_screen_button.cpp +++ b/scene/2d/touch_screen_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -129,8 +129,11 @@ void TouchScreenButton::_notification(int p_what) { if (shape.is_valid()) { Color draw_col = get_tree()->get_debug_collisions_color(); - Vector2 size = texture.is_null() ? shape->get_rect().size : texture->get_size(); - Vector2 pos = shape_centered ? size * 0.5f : Vector2(); + Vector2 pos; + if (shape_centered && texture.is_valid()) { + pos = texture->get_size() * 0.5; + } + draw_set_transform_matrix(get_canvas_transform().translated(pos)); shape->draw(get_canvas_item(), draw_col); } @@ -251,9 +254,12 @@ bool TouchScreenButton::_is_point_inside(const Point2 &p_point) { if (shape.is_valid()) { check_rect = false; - Vector2 size = texture.is_null() ? shape->get_rect().size : texture->get_size(); - Transform2D xform = shape_centered ? Transform2D().translated(size * 0.5f) : Transform2D(); - touched = shape->collide(xform, unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); + Vector2 pos; + if (shape_centered && texture.is_valid()) { + pos = texture->get_size() * 0.5; + } + + touched = shape->collide(Transform2D().translated(pos), unit_rect, Transform2D(0, coord + Vector2(0.5, 0.5))); } if (bitmask.is_valid()) { @@ -399,11 +405,6 @@ void TouchScreenButton::_bind_methods() { } TouchScreenButton::TouchScreenButton() { - finger_pressed = -1; - passby_press = false; - visibility = VISIBILITY_ALWAYS; - shape_centered = true; - shape_visible = true; unit_rect = Ref<RectangleShape2D>(memnew(RectangleShape2D)); - unit_rect->set_extents(Vector2(0.5, 0.5)); + unit_rect->set_size(Vector2(1, 1)); } diff --git a/scene/2d/touch_screen_button.h b/scene/2d/touch_screen_button.h index 287f886c2c..10820ad059 100644 --- a/scene/2d/touch_screen_button.h +++ b/scene/2d/touch_screen_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,16 +50,16 @@ private: Ref<Texture2D> texture_pressed; Ref<BitMap> bitmask; Ref<Shape2D> shape; - bool shape_centered; - bool shape_visible; + bool shape_centered = true; + bool shape_visible = true; Ref<RectangleShape2D> unit_rect; StringName action; - bool passby_press; - int finger_pressed; + bool passby_press = false; + int finger_pressed = -1; - VisibilityMode visibility; + VisibilityMode visibility = VISIBILITY_ALWAYS; void _input(const Ref<InputEvent> &p_event); diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index e217f2a394..916038a1f3 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -89,8 +89,6 @@ void VisibilityNotifier2D::set_rect(const Rect2 &p_rect) { item_rect_changed(); } } - - _change_notify("rect"); } Rect2 VisibilityNotifier2D::get_rect() const { @@ -317,7 +315,7 @@ String VisibilityEnabler2D::get_configuration_warning() const { #ifdef TOOLS_ENABLED if (is_inside_tree() && get_parent() && (get_parent()->get_filename() == String() && get_parent() != get_tree()->get_edited_scene_root())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("VisibilityEnabler2D works best when used with the edited scene root directly as parent."); @@ -363,6 +361,4 @@ VisibilityEnabler2D::VisibilityEnabler2D() { } enabler[ENABLER_PARENT_PROCESS] = false; enabler[ENABLER_PARENT_PHYSICS_PROCESS] = false; - - visible = false; } diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index 671378bd4e..3d1701a1e5 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -85,7 +85,7 @@ protected: virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible; + bool visible = false; void _find_nodes(Node *p_node); diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp index 7c2b41db70..7e7bc27cc2 100644 --- a/scene/2d/y_sort.cpp +++ b/scene/2d/y_sort.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,6 +48,5 @@ void YSort::_bind_methods() { } YSort::YSort() { - sort_enabled = true; RS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(), true); } diff --git a/scene/2d/y_sort.h b/scene/2d/y_sort.h index 62787d6744..7d36ee3391 100644 --- a/scene/2d/y_sort.h +++ b/scene/2d/y_sort.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,7 +35,7 @@ class YSort : public Node2D { GDCLASS(YSort, Node2D); - bool sort_enabled; + bool sort_enabled = true; static void _bind_methods(); public: diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp index b1adb0e88e..749cf4ff9d 100644 --- a/scene/3d/area_3d.cpp +++ b/scene/3d/area_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -211,7 +211,7 @@ void Area3D::_clear_monitoring() { Object *obj = ObjectDB::get_instance(E->key()); Node *node = Object::cast_to<Node>(obj); - if (!node) { //node may have been deleted in previous frame or at other legiminate point + if (!node) { //node may have been deleted in previous frame or at other legitimate point continue; } //ERR_CONTINUE(!node); @@ -240,7 +240,7 @@ void Area3D::_clear_monitoring() { Object *obj = ObjectDB::get_instance(E->key()); Node *node = Object::cast_to<Node>(obj); - if (!node) { //node may have been deleted in previous frame or at other legiminate point + if (!node) { //node may have been deleted in previous frame or at other legitimate point continue; } //ERR_CONTINUE(!node); @@ -640,13 +640,13 @@ void Area3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_reverb_uniformity", "amount"), &Area3D::set_reverb_uniformity); ClassDB::bind_method(D_METHOD("get_reverb_uniformity"), &Area3D::get_reverb_uniformity); - ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "area_shape"))); - ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("body_entered", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); + ADD_SIGNAL(MethodInfo("body_exited", PropertyInfo(Variant::OBJECT, "body", PROPERTY_HINT_RESOURCE_TYPE, "Node3D"))); - ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); - ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "self_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_entered", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); + ADD_SIGNAL(MethodInfo("area_shape_exited", PropertyInfo(Variant::INT, "area_id"), PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"), PropertyInfo(Variant::INT, "area_shape"), PropertyInfo(Variant::INT, "local_shape"))); ADD_SIGNAL(MethodInfo("area_entered", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"))); ADD_SIGNAL(MethodInfo("area_exited", PropertyInfo(Variant::OBJECT, "area", PROPERTY_HINT_RESOURCE_TYPE, "Area3D"))); @@ -681,29 +681,10 @@ void Area3D::_bind_methods() { Area3D::Area3D() : CollisionObject3D(PhysicsServer3D::get_singleton()->area_create(), true) { - space_override = SPACE_OVERRIDE_DISABLED; set_gravity(9.8); - locked = false; set_gravity_vector(Vector3(0, -1, 0)); - gravity_is_point = false; - gravity_distance_scale = 0; - linear_damp = 0.1; - angular_damp = 0.1; - priority = 0; - monitoring = false; - monitorable = false; - collision_mask = 1; - collision_layer = 1; set_monitoring(true); set_monitorable(true); - - audio_bus_override = false; - audio_bus = "Master"; - - use_reverb_bus = false; - reverb_bus = "Master"; - reverb_amount = 0.0; - reverb_uniformity = 0.0; } Area3D::~Area3D() { diff --git a/scene/3d/area_3d.h b/scene/3d/area_3d.h index 51f6317517..6d976115f7 100644 --- a/scene/3d/area_3d.h +++ b/scene/3d/area_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,19 +47,19 @@ public: }; private: - SpaceOverride space_override; + SpaceOverride space_override = SPACE_OVERRIDE_DISABLED; Vector3 gravity_vec; real_t gravity; - bool gravity_is_point; - real_t gravity_distance_scale; - real_t angular_damp; - real_t linear_damp; - uint32_t collision_mask; - uint32_t collision_layer; - int priority; - bool monitoring; - bool monitorable; - bool locked; + bool gravity_is_point = false; + real_t gravity_distance_scale = 0.0; + real_t angular_damp = 0.1; + real_t linear_damp = 0.1; + uint32_t collision_mask = 1; + uint32_t collision_layer = 1; + int priority = 0; + bool monitoring = false; + bool monitorable = false; + bool locked = false; void _body_inout(int p_status, const RID &p_body, ObjectID p_instance, int p_body_shape, int p_area_shape); @@ -67,8 +67,8 @@ private: void _body_exit_tree(ObjectID p_id); struct ShapePair { - int body_shape; - int area_shape; + int body_shape = 0; + int area_shape = 0; bool operator<(const ShapePair &p_sp) const { if (body_shape == p_sp.body_shape) { return area_shape < p_sp.area_shape; @@ -85,8 +85,8 @@ private: }; struct BodyState { - int rc; - bool in_tree; + int rc = 0; + bool in_tree = false; VSet<ShapePair> shapes; }; @@ -98,8 +98,8 @@ private: void _area_exit_tree(ObjectID p_id); struct AreaShapePair { - int area_shape; - int self_shape; + int area_shape = 0; + int self_shape = 0; bool operator<(const AreaShapePair &p_sp) const { if (area_shape == p_sp.area_shape) { return self_shape < p_sp.self_shape; @@ -116,21 +116,21 @@ private: }; struct AreaState { - int rc; - bool in_tree; + int rc = 0; + bool in_tree = false; VSet<AreaShapePair> shapes; }; Map<ObjectID, AreaState> area_map; void _clear_monitoring(); - bool audio_bus_override; - StringName audio_bus; + bool audio_bus_override = false; + StringName audio_bus = "Master"; - bool use_reverb_bus; - StringName reverb_bus; - float reverb_amount; - float reverb_uniformity; + bool use_reverb_bus = false; + StringName reverb_bus = "Master"; + float reverb_amount = 0.0; + float reverb_uniformity = 0.0; void _validate_property(PropertyInfo &property) const override; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index 2907eb3c7e..72392be5bd 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,8 +42,8 @@ class Spcap { private: struct Speaker { Vector3 direction; - real_t effective_number_of_speakers; // precalculated - mutable real_t squared_gain; // temporary + real_t effective_number_of_speakers = 0; // precalculated + mutable real_t squared_gain = 0; // temporary }; Vector<Speaker> speakers; @@ -138,15 +138,15 @@ void AudioStreamPlayer3D::_calc_output_vol(const Vector3 &source_dir, real_t tig } void AudioStreamPlayer3D::_mix_audio() { - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade_out)) { return; } bool started = false; - if (setseek >= 0.0) { - stream_playback->start(setseek); - setseek = -1.0; //reset seek + if (setseek.get() >= 0.0) { + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek started = true; } @@ -160,14 +160,14 @@ void AudioStreamPlayer3D::_mix_audio() { } // Mix if we're not paused or we're fading out - if ((output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { + if ((output_count.get() > 0 || out_of_range_mode == OUT_OF_RANGE_MIX)) { float output_pitch_scale = 0.0; - if (output_count) { + if (output_count.get()) { //used for doppler, not realistic but good enough - for (int i = 0; i < output_count; i++) { + for (int i = 0; i < output_count.get(); i++) { output_pitch_scale += outputs[i].pitch_scale; } - output_pitch_scale /= float(output_count); + output_pitch_scale /= float(output_count.get()); } else { output_pitch_scale = 1.0; } @@ -176,7 +176,7 @@ void AudioStreamPlayer3D::_mix_audio() { } //write all outputs - for (int i = 0; i < output_count; i++) { + for (int i = 0; i < output_count.get(); i++) { Output current = outputs[i]; //see if current output exists, to keep volume ramp @@ -285,14 +285,14 @@ void AudioStreamPlayer3D::_mix_audio() { prev_outputs[i] = current; } - prev_output_count = output_count; + prev_output_count = output_count.get(); //stream is no longer active, disable this. if (!stream_playback->is_playing()) { - active = false; + active.clear(); } - output_ready = false; + output_ready.clear(); stream_paused_fade_in = false; stream_paused_fade_out = false; } @@ -360,7 +360,7 @@ void AudioStreamPlayer3D::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) { //update anything related to position first, if possible of course - if (!output_ready) { + if (!output_ready.is_set()) { Vector3 linear_velocity; //compute linear velocity for doppler @@ -596,24 +596,20 @@ void AudioStreamPlayer3D::_notification(int p_what) { } } - output_count = new_output_count; - output_ready = true; + output_count.set(new_output_count); + output_ready.set(); } //start playing if requested - if (setplay >= 0.0) { - setseek = setplay; - active = true; - setplay = -1; - //do not update, this makes it easier to animate (will shut off otherwise) - ///_change_notify("playing"); //update property in editor + if (setplay.get() >= 0.0) { + setseek.set(setplay.get()); + active.set(); + setplay.set(-1); } //stop playing if no longer active - if (!active) { + if (!active.is_set()) { set_physics_process_internal(false); - //do not update, this makes it easier to animate (will shut off otherwise) - //_change_notify("playing"); //update property in editor emit_signal("finished"); } } @@ -627,8 +623,8 @@ void AudioStreamPlayer3D::set_stream(Ref<AudioStream> p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; + active.clear(); + setseek.set(-1); } if (p_stream.is_valid()) { @@ -687,30 +683,29 @@ void AudioStreamPlayer3D::play(float p_from_pos) { } if (stream_playback.is_valid()) { - active = true; - setplay = p_from_pos; - output_ready = false; + setplay.set(p_from_pos); + output_ready.clear(); set_physics_process_internal(true); } } void AudioStreamPlayer3D::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer3D::stop() { if (stream_playback.is_valid()) { - active = false; + active.clear(); set_physics_process_internal(false); - setplay = -1; + setplay.set(-1); } } bool AudioStreamPlayer3D::is_playing() const { if (stream_playback.is_valid()) { - return active; // && stream_playback->is_playing(); + return active.is_set() || setplay.get() >= 0; } return false; @@ -718,6 +713,10 @@ bool AudioStreamPlayer3D::is_playing() const { float AudioStreamPlayer3D::get_playback_position() { if (stream_playback.is_valid()) { + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; + } return stream_playback->get_playback_position(); } @@ -757,7 +756,7 @@ void AudioStreamPlayer3D::_set_playing(bool p_enable) { } bool AudioStreamPlayer3D::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { @@ -776,7 +775,7 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &property) const { } void AudioStreamPlayer3D::_bus_layout_changed() { - _change_notify(); + notify_property_list_changed(); } void AudioStreamPlayer3D::set_max_distance(float p_metres) { @@ -809,7 +808,6 @@ void AudioStreamPlayer3D::set_emission_angle(float p_angle) { ERR_FAIL_COND(p_angle < 0 || p_angle > 90); emission_angle = p_angle; update_gizmo(); - _change_notify("emission_angle"); } float AudioStreamPlayer3D::get_emission_angle() const { @@ -1002,31 +1000,6 @@ void AudioStreamPlayer3D::_bind_methods() { } AudioStreamPlayer3D::AudioStreamPlayer3D() { - unit_db = 0; - unit_size = 1; - attenuation_model = ATTENUATION_INVERSE_DISTANCE; - max_db = 3; - pitch_scale = 1.0; - autoplay = false; - setseek = -1; - active = false; - output_count = 0; - prev_output_count = 0; - max_distance = 0; - setplay = -1; - output_ready = false; - area_mask = 1; - emission_angle = 45; - emission_angle_enabled = false; - emission_angle_filter_attenuation_db = -12; - attenuation_filter_cutoff_hz = 5000; - attenuation_filter_db = -24; - out_of_range_mode = OUT_OF_RANGE_MIX; - doppler_tracking = DOPPLER_TRACKING_DISABLED; - stream_paused = false; - stream_paused_fade_in = false; - stream_paused_fade_out = false; - velocity_tracker.instance(); AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed)); set_disable_scale(true); diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h index 339475b469..70c535bd89 100644 --- a/scene/3d/audio_stream_player_3d.h +++ b/scene/3d/audio_stream_player_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_3D_H #define AUDIO_STREAM_PLAYER_3D_H +#include "core/templates/safe_refcount.h" #include "scene/3d/node_3d.h" #include "scene/3d/velocity_tracker_3d.h" #include "servers/audio/audio_filter_sw.h" @@ -71,46 +72,39 @@ private: AudioFilterSW filter; AudioFilterSW::Processor filter_process[8]; AudioFrame vol[4]; - float filter_gain; - float pitch_scale; - int bus_index; - int reverb_bus_index; + float filter_gain = 0.0; + float pitch_scale = 0.0; + int bus_index = -1; + int reverb_bus_index = -1; AudioFrame reverb_vol[4]; - Viewport *viewport; //pointer only used for reference to previous mix - - Output() { - filter_gain = 0; - viewport = nullptr; - reverb_bus_index = -1; - bus_index = -1; - } + Viewport *viewport = nullptr; //pointer only used for reference to previous mix }; Output outputs[MAX_OUTPUTS]; - volatile int output_count; - volatile bool output_ready; + SafeNumeric<int> output_count; + SafeFlag output_ready; //these are used by audio thread to have a reference of previous volumes (for ramping volume and avoiding clicks) Output prev_outputs[MAX_OUTPUTS]; - int prev_output_count; + int prev_output_count = 0; Ref<AudioStreamPlayback> stream_playback; Ref<AudioStream> stream; Vector<AudioFrame> mix_buffer; - volatile float setseek; - volatile bool active; - volatile float setplay; - - AttenuationModel attenuation_model; - float unit_db; - float unit_size; - float max_db; - float pitch_scale; - bool autoplay; - bool stream_paused; - bool stream_paused_fade_in; - bool stream_paused_fade_out; + SafeNumeric<float> setseek{ -1.0 }; + SafeFlag active; + SafeNumeric<float> setplay{ -1.0 }; + + AttenuationModel attenuation_model = ATTENUATION_INVERSE_DISTANCE; + float unit_db = 0.0; + float unit_size = 1.0; + float max_db = 3.0; + float pitch_scale = 1.0; + bool autoplay = false; + bool stream_paused = false; + bool stream_paused_fade_in = false; + bool stream_paused_fade_out = false; StringName bus; static void _calc_output_vol(const Vector3 &source_dir, real_t tightness, Output &output); @@ -122,21 +116,21 @@ private: void _bus_layout_changed(); - uint32_t area_mask; + uint32_t area_mask = 1; - bool emission_angle_enabled; - float emission_angle; - float emission_angle_filter_attenuation_db; - float attenuation_filter_cutoff_hz; - float attenuation_filter_db; + bool emission_angle_enabled = false; + float emission_angle = 45.0; + float emission_angle_filter_attenuation_db = -12.0; + float attenuation_filter_cutoff_hz = 5000.0; + float attenuation_filter_db = -24.0; - float max_distance; + float max_distance = 0.0; Ref<VelocityTracker3D> velocity_tracker; - DopplerTracking doppler_tracking; + DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED; - OutOfRangeMode out_of_range_mode; + OutOfRangeMode out_of_range_mode = OUT_OF_RANGE_MIX; float _get_attenuation_db(float p_distance) const; diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 38c9e96fbc..95ffbe48c1 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -78,6 +78,7 @@ void BakedLightmapData::clear_users() { } void BakedLightmapData::_set_user_data(const Array &p_data) { + ERR_FAIL_COND(p_data.size() <= 0); ERR_FAIL_COND((p_data.size() % 4) != 0); for (int i = 0; i < p_data.size(); i += 4) { @@ -195,7 +196,7 @@ void BakedLightmapData::_bind_methods() { ClassDB::bind_method(D_METHOD("set_uses_spherical_harmonics", "uses_spherical_harmonics"), &BakedLightmapData::set_uses_spherical_harmonics); ClassDB::bind_method(D_METHOD("is_using_spherical_harmonics"), &BakedLightmapData::is_using_spherical_harmonics); - ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "offset"), &BakedLightmapData::add_user); + ClassDB::bind_method(D_METHOD("add_user", "path", "uv_scale", "slice_index", "sub_instance"), &BakedLightmapData::add_user); ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count); ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path); ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users); @@ -448,7 +449,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const ERR_FAIL_COND_V(p_simplex_indices.size() <= 1, 0); //should not happen, this is a bug // Failed to separate the tetrahedrons using planes - // this means Delaunay borked at some point. + // this means Delaunay broke at some point. // Luckily, because we are using tetrahedrons, we can resort to // less precise but still working ways to generate the separating plane // this will most likely look bad when interpolating, but at least it will not crash. @@ -510,7 +511,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const node.plane = best_plane; if (indices_under.size() == 0) { - //noting to do here + //nothing to do here node.under = BSPNode::EMPTY_LEAF; } else if (indices_under.size() == 1) { node.under = -(indices_under[0] + 1); @@ -519,7 +520,7 @@ int32_t BakedLightmap::_compute_bsp_tree(const Vector<Vector3> &p_points, const } if (indices_over.size() == 0) { - //noting to do here + //nothing to do here node.over = BSPNode::EMPTY_LEAF; } else if (indices_over.size() == 1) { node.over = -(indices_over[0] + 1); @@ -659,7 +660,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d } // create mesh data for insert - //get the base material textures, help compute altlas size and bounds + //get the base material textures, help compute atlas size and bounds for (int m_i = 0; m_i < meshes_found.size(); m_i++) { if (p_bake_step) { float p = (float)(m_i) / meshes_found.size(); @@ -678,7 +679,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d } TypedArray<Image> images = RS::get_singleton()->bake_render_uv2(mf.mesh->get_rid(), overrides, lightmap_size); - ERR_FAIL_COND_V(images.empty(), BAKE_ERROR_CANT_CREATE_IMAGE); + ERR_FAIL_COND_V(images.is_empty(), BAKE_ERROR_CANT_CREATE_IMAGE); Ref<Image> albedo = images[RS::BAKE_CHANNEL_ALBEDO_ALPHA]; Ref<Image> orm = images[RS::BAKE_CHANNEL_ORM]; @@ -973,7 +974,7 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_image_d for (int i = 0; i < lightmapper->get_bake_texture_count(); i++) { images.push_back(lightmapper->get_bake_texture(i)); } - //we assume they are all the same, so lets create a large one for saving + //we assume they are all the same, so let's create a large one for saving Ref<Image> large_image; large_image.instance(); @@ -1302,7 +1303,7 @@ bool BakedLightmap::is_interior() const { void BakedLightmap::set_environment_mode(EnvironmentMode p_mode) { environment_mode = p_mode; - _change_notify(); + notify_property_list_changed(); } BakedLightmap::EnvironmentMode BakedLightmap::get_environment_mode() const { @@ -1466,17 +1467,4 @@ void BakedLightmap::_bind_methods() { } BakedLightmap::BakedLightmap() { - environment_mode = ENVIRONMENT_MODE_DISABLED; - environment_custom_color = Color(0.2, 0.7, 1.0); - environment_custom_energy = 1.0; - - bake_quality = BAKE_QUALITY_MEDIUM; - interior = false; - directional = false; - - gen_probes = GENERATE_PROBES_DISABLED; - use_denoiser = true; - bounces = 1; - bias = 0.0005; - max_texture_size = 16384; } diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h index 8808569215..e2d89ab2d0 100644 --- a/scene/3d/baked_lightmap.h +++ b/scene/3d/baked_lightmap.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -53,9 +53,9 @@ class BakedLightmapData : public Resource { struct User { NodePath path; - int32_t sub_instance; + int32_t sub_instance = 0; Rect2 uv_scale; - int slice_index; + int slice_index = 0; }; Vector<User> users; @@ -136,32 +136,32 @@ public: }; private: - BakeQuality bake_quality; - bool use_denoiser; - int bounces; - float bias; - int max_texture_size; - bool interior; - EnvironmentMode environment_mode; + BakeQuality bake_quality = BAKE_QUALITY_MEDIUM; + bool use_denoiser = true; + int bounces = 1; + float bias = 0.0005; + int max_texture_size = 16384; + bool interior = false; + EnvironmentMode environment_mode = ENVIRONMENT_MODE_DISABLED; Ref<Sky> environment_custom_sky; - Color environment_custom_color; - float environment_custom_energy; - bool directional; - GenerateProbes gen_probes; + Color environment_custom_color = Color(0.2, 0.7, 1.0); + float environment_custom_energy = 1.0; + bool directional = false; + GenerateProbes gen_probes = GENERATE_PROBES_DISABLED; Ref<BakedLightmapData> light_data; struct LightsFound { Transform xform; - Light3D *light; + Light3D *light = nullptr; }; struct MeshesFound { Transform xform; NodePath node_path; - int32_t subindex; + int32_t subindex = 0; Ref<Mesh> mesh; - int32_t lightmap_scale; + int32_t lightmap_scale = 0; Vector<Ref<Material>> overrides; }; @@ -172,19 +172,20 @@ private: struct BakeTimeData { String text; - int pass; - uint64_t last_step; + int pass = 0; + uint64_t last_step = 0; }; struct BSPSimplex { - int vertices[4]; - int planes[4]; + int vertices[4] = {}; + int planes[4] = {}; }; struct BSPNode { static const int32_t EMPTY_LEAF = INT32_MIN; Plane plane; - int32_t over = EMPTY_LEAF, under = EMPTY_LEAF; + int32_t over = EMPTY_LEAF; + int32_t under = EMPTY_LEAF; }; int _bsp_get_simplex_side(const Vector<Vector3> &p_points, const LocalVector<BSPSimplex> &p_simplices, const Plane &p_plane, uint32_t p_simplex) const; @@ -192,16 +193,16 @@ private: struct BakeStepUD { Lightmapper::BakeStepFunc func; - void *ud; - float from_percent; - float to_percent; + void *ud = nullptr; + float from_percent = 0.0; + float to_percent = 0.0; }; static bool _lightmap_bake_step_function(float p_completion, const String &p_text, void *ud, bool p_refresh); struct GenProbesOctree { Vector3i offset; - uint32_t size; + uint32_t size = 0; GenProbesOctree *children[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; ~GenProbesOctree() { for (int i = 0; i < 8; i++) { diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp index 68303bbfe5..5315e685a0 100644 --- a/scene/3d/bone_attachment_3d.cpp +++ b/scene/3d/bone_attachment_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -105,7 +105,6 @@ void BoneAttachment3D::_notification(int p_what) { } BoneAttachment3D::BoneAttachment3D() { - bound = false; } void BoneAttachment3D::_bind_methods() { diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h index 70b871430f..0c6d5f12b1 100644 --- a/scene/3d/bone_attachment_3d.h +++ b/scene/3d/bone_attachment_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class BoneAttachment3D : public Node3D { GDCLASS(BoneAttachment3D, Node3D); - bool bound; + bool bound = false; String bone_name; void _check_bind(); diff --git a/scene/3d/camera_3d.cpp b/scene/3d/camera_3d.cpp index 178c5c8ff8..cd8d02233b 100644 --- a/scene/3d/camera_3d.cpp +++ b/scene/3d/camera_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -102,7 +102,7 @@ void Camera3D::_update_camera() { void Camera3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_WORLD: { - // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD + // Needs to track the Viewport because it's needed on NOTIFICATION_EXIT_WORLD // and Spatial will handle it first, including clearing its reference to the Viewport, // therefore making it impossible to subclasses to access it viewport = get_viewport(); @@ -209,7 +209,7 @@ void Camera3D::set_projection(Camera3D::Projection p_mode) { if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL || p_mode == PROJECTION_FRUSTUM) { mode = p_mode; _update_camera_mode(); - _change_notify(); + notify_property_list_changed(); } } @@ -432,7 +432,7 @@ void Camera3D::set_keep_aspect_mode(KeepAspect p_aspect) { keep_aspect = p_aspect; RenderingServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH); _update_camera_mode(); - _change_notify(); + notify_property_list_changed(); } Camera3D::KeepAspect Camera3D::get_keep_aspect_mode() const { @@ -476,13 +476,13 @@ void Camera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_fov"), &Camera3D::get_fov); ClassDB::bind_method(D_METHOD("get_frustum_offset"), &Camera3D::get_frustum_offset); ClassDB::bind_method(D_METHOD("get_size"), &Camera3D::get_size); - ClassDB::bind_method(D_METHOD("get_zfar"), &Camera3D::get_zfar); - ClassDB::bind_method(D_METHOD("get_znear"), &Camera3D::get_znear); + ClassDB::bind_method(D_METHOD("get_far"), &Camera3D::get_far); + ClassDB::bind_method(D_METHOD("get_near"), &Camera3D::get_near); ClassDB::bind_method(D_METHOD("set_fov"), &Camera3D::set_fov); ClassDB::bind_method(D_METHOD("set_frustum_offset"), &Camera3D::set_frustum_offset); ClassDB::bind_method(D_METHOD("set_size"), &Camera3D::set_size); - ClassDB::bind_method(D_METHOD("set_zfar"), &Camera3D::set_zfar); - ClassDB::bind_method(D_METHOD("set_znear"), &Camera3D::set_znear); + ClassDB::bind_method(D_METHOD("set_far"), &Camera3D::set_far); + ClassDB::bind_method(D_METHOD("set_near"), &Camera3D::set_near); ClassDB::bind_method(D_METHOD("get_projection"), &Camera3D::get_projection); ClassDB::bind_method(D_METHOD("set_projection"), &Camera3D::set_projection); ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera3D::set_h_offset); @@ -519,8 +519,8 @@ void Camera3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frustum_offset"), "set_frustum_offset", "get_frustum_offset"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_znear", "get_znear"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_zfar", "get_zfar"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "near", PROPERTY_HINT_EXP_RANGE, "0.001,10,0.001,or_greater"), "set_near", "get_near"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4000,0.01,or_greater"), "set_far", "get_far"); BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE); BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL); @@ -542,7 +542,7 @@ float Camera3D::get_size() const { return size; } -float Camera3D::get_znear() const { +float Camera3D::get_near() const { return near; } @@ -550,7 +550,7 @@ Vector2 Camera3D::get_frustum_offset() const { return frustum_offset; } -float Camera3D::get_zfar() const { +float Camera3D::get_far() const { return far; } @@ -562,18 +562,16 @@ void Camera3D::set_fov(float p_fov) { ERR_FAIL_COND(p_fov < 1 || p_fov > 179); fov = p_fov; _update_camera_mode(); - _change_notify("fov"); } void Camera3D::set_size(float p_size) { ERR_FAIL_COND(p_size < 0.1 || p_size > 16384); size = p_size; _update_camera_mode(); - _change_notify("size"); } -void Camera3D::set_znear(float p_znear) { - near = p_znear; +void Camera3D::set_near(float p_near) { + near = p_near; _update_camera_mode(); } @@ -582,8 +580,8 @@ void Camera3D::set_frustum_offset(Vector2 p_offset) { _update_camera_mode(); } -void Camera3D::set_zfar(float p_zfar) { - far = p_zfar; +void Camera3D::set_far(float p_far) { + far = p_far; _update_camera_mode(); } @@ -653,24 +651,10 @@ Vector3 Camera3D::get_doppler_tracked_velocity() const { Camera3D::Camera3D() { camera = RenderingServer::get_singleton()->camera_create(); - size = 1; - fov = 0; - frustum_offset = Vector2(); - near = 0; - far = 0; - current = false; - viewport = nullptr; - force_change = false; - mode = PROJECTION_PERSPECTIVE; set_perspective(75.0, 0.05, 4000.0); - keep_aspect = KEEP_HEIGHT; - layers = 0xfffff; - v_offset = 0; - h_offset = 0; RenderingServer::get_singleton()->camera_set_cull_mask(camera, layers); //active=false; velocity_tracker.instance(); - doppler_tracking = DOPPLER_TRACKING_DISABLED; set_notify_transform(true); set_disable_scale(true); } @@ -689,17 +673,17 @@ float ClippedCamera3D::get_margin() const { return margin; } -void ClippedCamera3D::set_process_mode(ProcessMode p_mode) { - if (process_mode == p_mode) { +void ClippedCamera3D::set_process_callback(ClipProcessCallback p_mode) { + if (process_callback == p_mode) { return; } - process_mode = p_mode; - set_process_internal(process_mode == CLIP_PROCESS_IDLE); - set_physics_process_internal(process_mode == CLIP_PROCESS_PHYSICS); + process_callback = p_mode; + set_process_internal(process_callback == CLIP_PROCESS_IDLE); + set_physics_process_internal(process_callback == CLIP_PROCESS_PHYSICS); } -ClippedCamera3D::ProcessMode ClippedCamera3D::get_process_mode() const { - return process_mode; +ClippedCamera3D::ClipProcessCallback ClippedCamera3D::get_process_callback() const { + return process_callback; } Transform ClippedCamera3D::get_camera_transform() const { @@ -731,7 +715,7 @@ void ClippedCamera3D::_notification(int p_what) { Vector3 ray_from = parent_plane.project(cam_pos); - clip_offset = 0; //reset by defau;t + clip_offset = 0; //reset by default { //check if points changed Vector<Vector3> local_points = get_near_plane_points(); @@ -844,8 +828,8 @@ void ClippedCamera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_margin", "margin"), &ClippedCamera3D::set_margin); ClassDB::bind_method(D_METHOD("get_margin"), &ClippedCamera3D::get_margin); - ClassDB::bind_method(D_METHOD("set_process_mode", "process_mode"), &ClippedCamera3D::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &ClippedCamera3D::get_process_mode); + ClassDB::bind_method(D_METHOD("set_process_callback", "process_callback"), &ClippedCamera3D::set_process_callback); + ClassDB::bind_method(D_METHOD("get_process_callback"), &ClippedCamera3D::get_process_callback); ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &ClippedCamera3D::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &ClippedCamera3D::get_collision_mask); @@ -870,7 +854,7 @@ void ClippedCamera3D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_exceptions"), &ClippedCamera3D::clear_exceptions); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_margin", "get_margin"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_process_callback", "get_process_callback"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); ADD_GROUP("Clip To", "clip_to"); @@ -882,16 +866,10 @@ void ClippedCamera3D::_bind_methods() { } ClippedCamera3D::ClippedCamera3D() { - margin = 0; - clip_offset = 0; - process_mode = CLIP_PROCESS_PHYSICS; set_physics_process_internal(true); - collision_mask = 1; set_notify_local_transform(Engine::get_singleton()->is_editor_hint()); points.resize(5); pyramid_shape = PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CONVEX_POLYGON); - clip_to_areas = false; - clip_to_bodies = true; } ClippedCamera3D::~ClippedCamera3D() { diff --git a/scene/3d/camera_3d.h b/scene/3d/camera_3d.h index 04cec92b14..cea61e4db8 100644 --- a/scene/3d/camera_3d.h +++ b/scene/3d/camera_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -57,26 +57,27 @@ public: }; private: - bool force_change; - bool current; - Viewport *viewport; + bool force_change = false; + bool current = false; + Viewport *viewport = nullptr; - Projection mode; + Projection mode = PROJECTION_PERSPECTIVE; - float fov; - float size; + float fov = 0.0; + float size = 1.0; Vector2 frustum_offset; - float near, far; - float v_offset; - float h_offset; - KeepAspect keep_aspect; + float near = 0.0; + float far = 0.0; + float v_offset = 0.0; + float h_offset = 0.0; + KeepAspect keep_aspect = KEEP_HEIGHT; RID camera; RID scenario_id; // String camera_group; - uint32_t layers; + uint32_t layers = 0xfffff; Ref<Environment> environment; Ref<CameraEffects> effects; @@ -87,7 +88,7 @@ private: friend class Viewport; void _update_audio_listener_state(); - DopplerTracking doppler_tracking; + DopplerTracking doppler_tracking = DOPPLER_TRACKING_DISABLED; Ref<VelocityTracker3D> velocity_tracker; protected: @@ -121,16 +122,16 @@ public: float get_fov() const; float get_size() const; - float get_zfar() const; - float get_znear() const; + float get_far() const; + float get_near() const; Vector2 get_frustum_offset() const; Projection get_projection() const; void set_fov(float p_fov); void set_size(float p_size); - void set_zfar(float p_zfar); - void set_znear(float p_znear); + void set_far(float p_far); + void set_near(float p_near); void set_frustum_offset(Vector2 p_offset); virtual Transform get_camera_transform() const; @@ -185,19 +186,19 @@ class ClippedCamera3D : public Camera3D { GDCLASS(ClippedCamera3D, Camera3D); public: - enum ProcessMode { + enum ClipProcessCallback { CLIP_PROCESS_PHYSICS, CLIP_PROCESS_IDLE, }; private: - ProcessMode process_mode; + ClipProcessCallback process_callback = CLIP_PROCESS_PHYSICS; RID pyramid_shape; - float margin; - float clip_offset; - uint32_t collision_mask; - bool clip_to_areas; - bool clip_to_bodies; + float margin = 0.0; + float clip_offset = 0.0; + uint32_t collision_mask = 1; + bool clip_to_areas = false; + bool clip_to_bodies = true; Set<RID> exclude; @@ -218,8 +219,8 @@ public: void set_margin(float p_margin); float get_margin() const; - void set_process_mode(ProcessMode p_mode); - ProcessMode get_process_mode() const; + void set_process_callback(ClipProcessCallback p_mode); + ClipProcessCallback get_process_callback() const; void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; @@ -239,5 +240,5 @@ public: ~ClippedCamera3D(); }; -VARIANT_ENUM_CAST(ClippedCamera3D::ProcessMode); +VARIANT_ENUM_CAST(ClippedCamera3D::ClipProcessCallback); #endif diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 356992e922..39880db29c 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -30,6 +30,8 @@ #include "collision_object_3d.h" +#include "core/config/engine.h" +#include "mesh_instance_3d.h" #include "scene/scene_string_names.h" #include "servers/physics_server_3d.h" @@ -110,6 +112,42 @@ void CollisionObject3D::_update_pickable() { } } +void CollisionObject3D::_update_debug_shapes() { + for (Set<uint32_t>::Element *shapedata_idx = debug_shapes_to_update.front(); shapedata_idx; shapedata_idx = shapedata_idx->next()) { + if (shapes.has(shapedata_idx->get())) { + ShapeData &shapedata = shapes[shapedata_idx->get()]; + for (int i = 0; i < shapedata.shapes.size(); i++) { + ShapeData::ShapeBase &s = shapedata.shapes.write[i]; + if (s.debug_shape) { + s.debug_shape->queue_delete(); + s.debug_shape = nullptr; + } + if (s.shape.is_null() || shapedata.disabled) { + continue; + } + + Ref<Mesh> mesh = s.shape->get_debug_mesh(); + MeshInstance3D *mi = memnew(MeshInstance3D); + mi->set_transform(shapedata.xform); + mi->set_mesh(mesh); + add_child(mi); + mi->force_update_transform(); + s.debug_shape = mi; + } + } + } + debug_shapes_to_update.clear(); +} + +void CollisionObject3D::_update_shape_data(uint32_t p_owner) { + if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !Engine::get_singleton()->is_editor_hint()) { + if (debug_shapes_to_update.is_empty()) { + call_deferred("_update_debug_shapes"); + } + debug_shapes_to_update.insert(p_owner); + } +} + void CollisionObject3D::set_ray_pickable(bool p_ray_pickable) { ray_pickable = p_ray_pickable; _update_pickable(); @@ -141,6 +179,8 @@ void CollisionObject3D::_bind_methods() { ClassDB::bind_method(D_METHOD("shape_owner_clear_shapes", "owner_id"), &CollisionObject3D::shape_owner_clear_shapes); ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner); + ClassDB::bind_method(D_METHOD("_update_debug_shapes"), &CollisionObject3D::_update_debug_shapes); + BIND_VMETHOD(MethodInfo("_input_event", PropertyInfo(Variant::OBJECT, "camera"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "click_position"), PropertyInfo(Variant::VECTOR3, "click_normal"), PropertyInfo(Variant::INT, "shape_idx"))); @@ -188,6 +228,7 @@ void CollisionObject3D::shape_owner_set_disabled(uint32_t p_owner, bool p_disabl PhysicsServer3D::get_singleton()->body_set_shape_disabled(rid, sd.shapes[i].index, p_disabled); } } + _update_shape_data(p_owner); } bool CollisionObject3D::is_shape_owner_disabled(uint32_t p_owner) const { @@ -223,6 +264,8 @@ void CollisionObject3D::shape_owner_set_transform(uint32_t p_owner, const Transf PhysicsServer3D::get_singleton()->body_set_shape_transform(rid, sd.shapes[i].index, p_transform); } } + + _update_shape_data(p_owner); } Transform CollisionObject3D::shape_owner_get_transform(uint32_t p_owner) const { @@ -245,6 +288,7 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3 ShapeData::ShapeBase s; s.index = total_subshapes; s.shape = p_shape; + if (area) { PhysicsServer3D::get_singleton()->area_add_shape(rid, p_shape->get_rid(), sd.xform, sd.disabled); } else { @@ -253,6 +297,8 @@ void CollisionObject3D::shape_owner_add_shape(uint32_t p_owner, const Ref<Shape3 sd.shapes.push_back(s); total_subshapes++; + + _update_shape_data(p_owner); } int CollisionObject3D::shape_owner_get_shape_count(uint32_t p_owner) const { @@ -279,13 +325,19 @@ void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) ERR_FAIL_COND(!shapes.has(p_owner)); ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size()); - int index_to_remove = shapes[p_owner].shapes[p_shape].index; + const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape]; + int index_to_remove = s.index; + if (area) { PhysicsServer3D::get_singleton()->area_remove_shape(rid, index_to_remove); } else { PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove); } + if (s.debug_shape) { + s.debug_shape->queue_delete(); + } + shapes[p_owner].shapes.remove(p_shape); for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) { @@ -325,10 +377,7 @@ uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const { CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) { rid = p_rid; area = p_area; - capture_input_on_drag = false; - ray_pickable = true; set_notify_transform(true); - total_subshapes = 0; if (p_area) { PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id()); @@ -349,8 +398,8 @@ bool CollisionObject3D::get_capture_input_on_drag() const { String CollisionObject3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); - if (shapes.empty()) { - if (!warning.empty()) { + if (shapes.is_empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape."); @@ -360,8 +409,6 @@ String CollisionObject3D::get_configuration_warning() const { } CollisionObject3D::CollisionObject3D() { - capture_input_on_drag = false; - ray_pickable = true; set_notify_transform(true); //owner= diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index 39e7df40a8..fe20176984 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,36 +37,36 @@ class CollisionObject3D : public Node3D { GDCLASS(CollisionObject3D, Node3D); - bool area; + bool area = false; RID rid; struct ShapeData { - Object *owner; + Object *owner = nullptr; Transform xform; struct ShapeBase { + Node *debug_shape = nullptr; Ref<Shape3D> shape; - int index; + int index = 0; }; Vector<ShapeBase> shapes; - bool disabled; - - ShapeData() { - disabled = false; - owner = nullptr; - } + bool disabled = false; }; - int total_subshapes; + int total_subshapes = 0; Map<uint32_t, ShapeData> shapes; - bool capture_input_on_drag; - bool ray_pickable; + bool capture_input_on_drag = false; + bool ray_pickable = true; + + Set<uint32_t> debug_shapes_to_update; void _update_pickable(); + void _update_shape_data(uint32_t p_owner); + protected: CollisionObject3D(RID p_rid, bool p_area); @@ -77,6 +77,8 @@ protected: virtual void _mouse_enter(); virtual void _mouse_exit(); + void _update_debug_shapes(); + public: uint32_t create_shape_owner(Object *p_owner); void remove_shape_owner(uint32_t owner); diff --git a/scene/3d/collision_polygon_3d.cpp b/scene/3d/collision_polygon_3d.cpp index b8a4ab74ee..e3e2eb4669 100644 --- a/scene/3d/collision_polygon_3d.cpp +++ b/scene/3d/collision_polygon_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -70,6 +70,7 @@ void CollisionPolygon3D::_build_polygon() { } convex->set_points(cp); + convex->set_margin(margin); parent->shape_owner_add_shape(owner_id, convex); parent->shape_owner_set_disabled(owner_id, disabled); } @@ -132,13 +133,13 @@ AABB CollisionPolygon3D::get_item_rect() const { return aabb; } -void CollisionPolygon3D::set_depth(float p_depth) { +void CollisionPolygon3D::set_depth(real_t p_depth) { depth = p_depth; _build_polygon(); update_gizmo(); } -float CollisionPolygon3D::get_depth() const { +real_t CollisionPolygon3D::get_depth() const { return depth; } @@ -155,18 +156,29 @@ bool CollisionPolygon3D::is_disabled() const { return disabled; } +real_t CollisionPolygon3D::get_margin() const { + return margin; +} + +void CollisionPolygon3D::set_margin(real_t p_margin) { + margin = p_margin; + if (parent) { + _build_polygon(); + } +} + String CollisionPolygon3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_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()) { - if (!warning.empty()) { + if (polygon.is_empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("An empty CollisionPolygon3D has no effect on collision."); @@ -189,18 +201,17 @@ void CollisionPolygon3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon3D::set_disabled); ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon3D::is_disabled); + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &CollisionPolygon3D::set_margin); + ClassDB::bind_method(D_METHOD("get_margin"), &CollisionPolygon3D::get_margin); + ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon3D::_is_editable_3d_polygon); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth"), "set_depth", "get_depth"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0.001,10,0.001"), "set_margin", "get_margin"); } CollisionPolygon3D::CollisionPolygon3D() { - aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); - depth = 1.0; set_notify_local_transform(true); - parent = nullptr; - owner_id = 0; - disabled = false; } diff --git a/scene/3d/collision_polygon_3d.h b/scene/3d/collision_polygon_3d.h index bab85b6011..750751b509 100644 --- a/scene/3d/collision_polygon_3d.h +++ b/scene/3d/collision_polygon_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,16 +37,17 @@ class CollisionObject3D; class CollisionPolygon3D : public Node3D { GDCLASS(CollisionPolygon3D, Node3D); + real_t margin = 0.04; protected: - float depth; - AABB aabb; + real_t depth = 1.0; + AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); Vector<Point2> polygon; - uint32_t owner_id; - CollisionObject3D *parent; + uint32_t owner_id = 0; + CollisionObject3D *parent = nullptr; - bool disabled; + bool disabled = false; void _build_polygon(); @@ -59,8 +60,8 @@ protected: static void _bind_methods(); public: - void set_depth(float p_depth); - float get_depth() const; + void set_depth(real_t p_depth); + real_t get_depth() const; void set_polygon(const Vector<Point2> &p_polygon); Vector<Point2> get_polygon() const; @@ -70,6 +71,9 @@ public: virtual AABB get_item_rect() const; + real_t get_margin() const; + void set_margin(real_t p_margin); + String get_configuration_warning() const override; CollisionPolygon3D(); diff --git a/scene/3d/collision_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index e1c691b89a..242d82ab4c 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -60,7 +60,7 @@ void CollisionShape3D::make_convex_from_siblings() { if (m.is_valid()) { for (int j = 0; j < m->get_surface_count(); j++) { Array a = m->surface_get_arrays(j); - if (!a.empty()) { + if (!a.is_empty()) { Vector<Vector3> v = a[RenderingServer::ARRAY_VERTEX]; for (int k = 0; k < v.size(); k++) { vertices.append(mi->get_transform().xform(v[k])); @@ -100,9 +100,6 @@ void CollisionShape3D::_notification(int p_what) { if (parent) { _update_in_shape_owner(); } - if (get_tree()->is_debugging_collisions_hint()) { - _update_debug_shape(); - } } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (parent) { @@ -127,14 +124,14 @@ String CollisionShape3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (!Object::cast_to<CollisionObject3D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_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()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("A shape must be provided for CollisionShape3D to function. Please create a shape resource for it."); @@ -144,7 +141,7 @@ String CollisionShape3D::get_configuration_warning() const { 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()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("ConcavePolygonShape3D doesn't support RigidBody3D in another mode than static."); @@ -163,13 +160,14 @@ void CollisionShape3D::_bind_methods() { 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); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled"); } void CollisionShape3D::set_shape(const Ref<Shape3D> &p_shape) { + if (p_shape == shape) { + return; + } if (!shape.is_null()) { shape->unregister_owner(this); shape->disconnect("changed", callable_mp(this, &CollisionShape3D::_shape_changed)); @@ -211,10 +209,6 @@ bool CollisionShape3D::is_disabled() const { CollisionShape3D::CollisionShape3D() { //indicator = RenderingServer::get_singleton()->mesh_create(); - disabled = false; - debug_shape = nullptr; - parent = nullptr; - owner_id = 0; set_notify_local_transform(true); } @@ -225,34 +219,9 @@ CollisionShape3D::~CollisionShape3D() { //RenderingServer::get_singleton()->free(indicator); } -void CollisionShape3D::_update_debug_shape() { - debug_shape_dirty = false; - - if (debug_shape) { - debug_shape->queue_delete(); - debug_shape = nullptr; - } - - Ref<Shape3D> s = get_shape(); - if (s.is_null()) { - return; - } - - Ref<Mesh> mesh = s->get_debug_mesh(); - MeshInstance3D *mi = memnew(MeshInstance3D); - mi->set_mesh(mesh); - add_child(mi); - debug_shape = mi; -} - void CollisionShape3D::_shape_changed() { // If this is a heightfield shape our center may have changed if (parent) { _update_in_shape_owner(true); } - - if (is_inside_tree() && get_tree()->is_debugging_collisions_hint() && !debug_shape_dirty) { - debug_shape_dirty = true; - call_deferred("_update_debug_shape"); - } } diff --git a/scene/3d/collision_shape_3d.h b/scene/3d/collision_shape_3d.h index 35f40d27b1..5512417f75 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,17 +40,13 @@ class CollisionShape3D : public Node3D { Ref<Shape3D> shape; - uint32_t owner_id; - CollisionObject3D *parent; - - Node *debug_shape; - bool debug_shape_dirty; + uint32_t owner_id = 0; + CollisionObject3D *parent = nullptr; void resource_changed(RES res); - bool disabled; + bool disabled = false; protected: - void _update_debug_shape(); void _shape_changed(); void _update_in_shape_owner(bool p_xform_only = false); diff --git a/scene/3d/cpu_particles_3d.cpp b/scene/3d/cpu_particles_3d.cpp index 215d9e062c..d22d7ff3ab 100644 --- a/scene/3d/cpu_particles_3d.cpp +++ b/scene/3d/cpu_particles_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -73,7 +73,7 @@ void CPUParticles3D::set_amount(int p_amount) { } particle_data.resize((12 + 4 + 4) * p_amount); - RS::get_singleton()->multimesh_allocate(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true); + RS::get_singleton()->multimesh_allocate_data(multimesh, p_amount, RS::MULTIMESH_TRANSFORM_3D, true, true); particle_order.resize(p_amount); } @@ -152,6 +152,7 @@ float CPUParticles3D::get_speed_scale() const { } void CPUParticles3D::set_draw_order(DrawOrder p_order) { + ERR_FAIL_INDEX(p_order, DRAW_ORDER_MAX); draw_order = p_order; } @@ -372,7 +373,7 @@ void CPUParticles3D::set_particle_flag(ParticleFlags p_particle_flag, bool p_ena ERR_FAIL_INDEX(p_particle_flag, PARTICLE_FLAG_MAX); particle_flags[p_particle_flag] = p_enable; if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { - _change_notify(); + notify_property_list_changed(); } } @@ -575,7 +576,7 @@ void CPUParticles3D::_particles_process(float p_delta) { cycle++; if (one_shot && cycle > 0) { set_emitting(false); - _change_notify(); + notify_property_list_changed(); } } @@ -646,6 +647,8 @@ void CPUParticles3D::_particles_process(float p_delta) { restart = true; } + float tv = 0.0; + if (restart) { if (!emitting) { p.active = false; @@ -660,12 +663,12 @@ void CPUParticles3D::_particles_process(float p_delta) { float tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(0); + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } float tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(0); + tex_anim_offset = curve_parameters[PARAM_ANGLE]->interpolate(tv); } p.seed = Math::rand(); @@ -676,13 +679,13 @@ void CPUParticles3D::_particles_process(float p_delta) { p.anim_offset_rand = Math::randf(); if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { - float angle1_rad = Math::atan2(direction.y, direction.x) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; + float angle1_rad = Math::atan2(direction.y, direction.x) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); Vector3 rot = Vector3(Math::cos(angle1_rad), Math::sin(angle1_rad), 0.0); p.velocity = rot * parameters[PARAM_INITIAL_LINEAR_VELOCITY] * Math::lerp(1.0f, float(Math::randf()), randomness[PARAM_INITIAL_LINEAR_VELOCITY]); } else { //initiate velocity spread in 3D - float angle1_rad = Math::atan2(direction.x, direction.z) + (Math::randf() * 2.0 - 1.0) * Math_PI * spread / 180.0; - float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + (Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * Math_PI * spread / 180.0; + float angle1_rad = Math::atan2(direction.x, direction.z) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * spread); + float angle2_rad = Math::atan2(direction.y, Math::abs(direction.z)) + Math::deg2rad((Math::randf() * 2.0 - 1.0) * (1.0 - flatness) * spread); Vector3 direction_xz = Vector3(Math::sin(angle1_rad), 0, Math::cos(angle1_rad)); Vector3 direction_yz = Vector3(0, Math::sin(angle2_rad), Math::cos(angle2_rad)); @@ -706,8 +709,9 @@ void CPUParticles3D::_particles_process(float p_delta) { //do none } break; case EMISSION_SHAPE_SPHERE: { - float s = 2.0 * Math::randf() - 1.0, t = 2.0 * Math_PI * Math::randf(); - float radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); + real_t s = 2.0 * Math::randf() - 1.0; + real_t t = Math_TAU * Math::randf(); + real_t radius = emission_sphere_radius * Math::sqrt(1.0 - s * s); p.transform.origin = Vector3(radius * Math::cos(t), radius * Math::sin(t), emission_sphere_radius * s); } break; case EMISSION_SHAPE_BOX: { @@ -730,7 +734,7 @@ void CPUParticles3D::_particles_process(float p_delta) { Vector2 normal_2d(normal.x, normal.y); Transform2D m2; m2.set_axis(0, normal_2d); - m2.set_axis(1, normal_2d.tangent()); + m2.set_axis(1, normal_2d.orthogonal()); Vector2 velocity_2d(p.velocity.x, p.velocity.y); velocity_2d = m2.basis_xform(velocity_2d); p.velocity.x = velocity_2d.x; @@ -771,61 +775,63 @@ void CPUParticles3D::_particles_process(float p_delta) { continue; } else if (p.time > p.lifetime) { p.active = false; + tv = 1.0; } else { uint32_t alt_seed = p.seed; p.time += local_delta; p.custom[1] = p.time / lifetime; + tv = p.time / p.lifetime; float tex_linear_velocity = 0.0; if (curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(p.custom[1]); + tex_linear_velocity = curve_parameters[PARAM_INITIAL_LINEAR_VELOCITY]->interpolate(tv); } float tex_orbit_velocity = 0.0; if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (curve_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(p.custom[1]); + tex_orbit_velocity = curve_parameters[PARAM_ORBIT_VELOCITY]->interpolate(tv); } } float tex_angular_velocity = 0.0; if (curve_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(p.custom[1]); + tex_angular_velocity = curve_parameters[PARAM_ANGULAR_VELOCITY]->interpolate(tv); } float tex_linear_accel = 0.0; if (curve_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(p.custom[1]); + tex_linear_accel = curve_parameters[PARAM_LINEAR_ACCEL]->interpolate(tv); } float tex_tangential_accel = 0.0; if (curve_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(p.custom[1]); + tex_tangential_accel = curve_parameters[PARAM_TANGENTIAL_ACCEL]->interpolate(tv); } float tex_radial_accel = 0.0; if (curve_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(p.custom[1]); + tex_radial_accel = curve_parameters[PARAM_RADIAL_ACCEL]->interpolate(tv); } float tex_damping = 0.0; if (curve_parameters[PARAM_DAMPING].is_valid()) { - tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(p.custom[1]); + tex_damping = curve_parameters[PARAM_DAMPING]->interpolate(tv); } float tex_angle = 0.0; if (curve_parameters[PARAM_ANGLE].is_valid()) { - tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(p.custom[1]); + tex_angle = curve_parameters[PARAM_ANGLE]->interpolate(tv); } float tex_anim_speed = 0.0; if (curve_parameters[PARAM_ANIM_SPEED].is_valid()) { - tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(p.custom[1]); + tex_anim_speed = curve_parameters[PARAM_ANIM_SPEED]->interpolate(tv); } float tex_anim_offset = 0.0; if (curve_parameters[PARAM_ANIM_OFFSET].is_valid()) { - tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(p.custom[1]); + tex_anim_offset = curve_parameters[PARAM_ANIM_OFFSET]->interpolate(tv); } Vector3 force = gravity; @@ -855,7 +861,7 @@ void CPUParticles3D::_particles_process(float p_delta) { if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { float orbit_amount = (parameters[PARAM_ORBIT_VELOCITY] + tex_orbit_velocity) * Math::lerp(1.0f, rand_from_seed(alt_seed), randomness[PARAM_ORBIT_VELOCITY]); if (orbit_amount != 0.0) { - float ang = orbit_amount * local_delta * Math_PI * 2.0; + float ang = orbit_amount * local_delta * Math_TAU; // Not sure why the ParticlesMaterial code uses a clockwise rotation matrix, // but we use -ang here to reproduce its behavior. Transform2D rot = Transform2D(-ang, Vector2()); @@ -887,15 +893,15 @@ void CPUParticles3D::_particles_process(float p_delta) { float tex_scale = 1.0; if (curve_parameters[PARAM_SCALE].is_valid()) { - tex_scale = curve_parameters[PARAM_SCALE]->interpolate(p.custom[1]); + tex_scale = curve_parameters[PARAM_SCALE]->interpolate(tv); } float tex_hue_variation = 0.0; if (curve_parameters[PARAM_HUE_VARIATION].is_valid()) { - tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(p.custom[1]); + tex_hue_variation = curve_parameters[PARAM_HUE_VARIATION]->interpolate(tv); } - float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_PI * 2.0 * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); + float hue_rot_angle = (parameters[PARAM_HUE_VARIATION] + tex_hue_variation) * Math_TAU * Math::lerp(1.0f, p.hue_rot_rand * 2.0f - 1.0f, randomness[PARAM_HUE_VARIATION]); float hue_rot_c = Math::cos(hue_rot_angle); float hue_rot_s = Math::sin(hue_rot_angle); @@ -911,7 +917,7 @@ void CPUParticles3D::_particles_process(float p_delta) { } if (color_ramp.is_valid()) { - p.color = color_ramp->get_color_at_offset(p.custom[1]) * color; + p.color = color_ramp->get_color_at_offset(tv) * color; } else { p.color = color; } @@ -1006,6 +1012,7 @@ void CPUParticles3D::_update_particle_data_buffer() { sorter.compare.particles = r; sorter.sort(order, pc); } else if (draw_order == DRAW_ORDER_VIEW_DEPTH) { + ERR_FAIL_NULL(get_viewport()); Camera3D *c = get_viewport()->get_camera(); if (c) { Vector3 dir = c->get_global_transform().basis.get_axis(2); //far away to close @@ -1067,7 +1074,7 @@ void CPUParticles3D::_update_particle_data_buffer() { ptr += 20; } - can_update = true; + can_update.set(); } void CPUParticles3D::_set_redraw(bool p_redraw) { @@ -1096,9 +1103,9 @@ void CPUParticles3D::_set_redraw(bool p_redraw) { void CPUParticles3D::_update_render_thread() { MutexLock lock(update_mutex); - if (can_update) { + if (can_update.is_set()) { RS::get_singleton()->multimesh_set_buffer(multimesh, particle_data); - can_update = false; //wait for next time + can_update.clear(); //wait for next time } } @@ -1160,7 +1167,7 @@ void CPUParticles3D::_notification(int p_what) { ptr += 20; } - can_update = true; + can_update.set(); } } } @@ -1440,13 +1447,6 @@ void CPUParticles3D::_bind_methods() { } CPUParticles3D::CPUParticles3D() { - time = 0; - inactive_time = 0; - frame_remainder = 0; - cycle = 0; - redraw = false; - emitting = false; - set_notify_transform(true); multimesh = RenderingServer::get_singleton()->multimesh_create(); @@ -1454,23 +1454,8 @@ CPUParticles3D::CPUParticles3D() { set_base(multimesh); set_emitting(true); - set_one_shot(false); set_amount(8); - set_lifetime(1); - set_fixed_fps(0); - set_fractional_delta(true); - set_pre_process_time(0); - set_explosiveness_ratio(0); - set_randomness_ratio(0); - set_lifetime_randomness(0); - set_use_local_coordinates(true); - - set_draw_order(DRAW_ORDER_INDEX); - set_speed_scale(1); - - set_direction(Vector3(1, 0, 0)); - set_spread(45); - set_flatness(0); + set_param(PARAM_INITIAL_LINEAR_VELOCITY, 0); set_param(PARAM_ANGULAR_VELOCITY, 0); set_param(PARAM_ORBIT_VELOCITY, 0); @@ -1497,8 +1482,6 @@ CPUParticles3D::CPUParticles3D() { particle_flags[i] = false; } - can_update = false; - set_color(Color(1, 1, 1, 1)); } diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 8c1b8a684c..10ac32622d 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,6 +32,7 @@ #define CPU_PARTICLES_H #include "core/templates/rid.h" +#include "core/templates/safe_refcount.h" #include "scene/3d/visual_instance_3d.h" class CPUParticles3D : public GeometryInstance3D { @@ -43,6 +44,7 @@ public: DRAW_ORDER_INDEX, DRAW_ORDER_LIFETIME, DRAW_ORDER_VIEW_DEPTH, + DRAW_ORDER_MAX }; enum Parameter { @@ -78,30 +80,30 @@ public: }; private: - bool emitting; + bool emitting = false; struct Particle { Transform transform; Color color; - float custom[4]; + float custom[4] = {}; Vector3 velocity; - bool active; - float angle_rand; - float scale_rand; - float hue_rot_rand; - float anim_offset_rand; - float time; - float lifetime; + bool active = false; + float angle_rand = 0.0; + float scale_rand = 0.0; + float hue_rot_rand = 0.0; + float anim_offset_rand = 0.0; + float time = 0.0; + float lifetime = 0.0; Color base_color; - uint32_t seed; + uint32_t seed = 0; }; - float time; - float inactive_time; - float frame_remainder; - int cycle; - bool redraw; + float time = 0.0; + float inactive_time = 0.0; + float frame_remainder = 0.0; + int cycle = 0; + bool redraw = false; RID multimesh; @@ -110,7 +112,7 @@ private: Vector<int> particle_order; struct SortLifetime { - const Particle *particles; + const Particle *particles = nullptr; bool operator()(int p_a, int p_b) const { return particles[p_a].time > particles[p_b].time; @@ -118,7 +120,7 @@ private: }; struct SortAxis { - const Particle *particles; + const Particle *particles = nullptr; Vector3 axis; bool operator()(int p_a, int p_b) const { return axis.dot(particles[p_a].transform.origin) < axis.dot(particles[p_b].transform.origin); @@ -127,50 +129,50 @@ private: // - bool one_shot; + bool one_shot = false; - float lifetime; - float pre_process_time; - float explosiveness_ratio; - float randomness_ratio; - float lifetime_randomness; - float speed_scale; - bool local_coords; - int fixed_fps; - bool fractional_delta; + float lifetime = 1.0; + float pre_process_time = 0.0; + float explosiveness_ratio = 0.0; + float randomness_ratio = 0.0; + float lifetime_randomness = 0.0; + float speed_scale = 1.0; + bool local_coords = true; + int fixed_fps = 0; + bool fractional_delta = true; Transform inv_emission_transform; - volatile bool can_update; + SafeFlag can_update; - DrawOrder draw_order; + DrawOrder draw_order = DRAW_ORDER_INDEX; Ref<Mesh> mesh; //////// - Vector3 direction; - float spread; - float flatness; + Vector3 direction = Vector3(1, 0, 0); + float spread = 45.0; + float flatness = 0.0; float parameters[PARAM_MAX]; - float randomness[PARAM_MAX]; + float randomness[PARAM_MAX] = {}; Ref<Curve> curve_parameters[PARAM_MAX]; - Color color; + Color color = Color(1, 1, 1, 1); Ref<Gradient> color_ramp; - bool particle_flags[PARTICLE_FLAG_MAX]; + bool particle_flags[PARTICLE_FLAG_MAX] = {}; - EmissionShape emission_shape; - float emission_sphere_radius; - Vector3 emission_box_extents; + EmissionShape emission_shape = EMISSION_SHAPE_POINT; + float emission_sphere_radius = 1.0; + Vector3 emission_box_extents = Vector3(1, 1, 1); Vector<Vector3> emission_points; Vector<Vector3> emission_normals; Vector<Color> emission_colors; - int emission_point_count; + int emission_point_count = 0; - Vector3 gravity; + Vector3 gravity = Vector3(0, -9.8, 0); void _update_internal(); void _particles_process(float p_delta); diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index fb72e10171..7d6abe458a 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,7 +34,6 @@ void Decal::set_extents(const Vector3 &p_extents) { extents = p_extents; RS::get_singleton()->decal_set_extents(decal, p_extents); update_gizmo(); - _change_notify("extents"); } Vector3 Decal::get_extents() const { @@ -110,6 +109,7 @@ Color Decal::get_modulate() const { void Decal::set_enable_distance_fade(bool p_enable) { distance_fade_enabled = p_enable; RS::get_singleton()->decal_set_distance_fade(decal, distance_fade_enabled, distance_fade_begin, distance_fade_length); + notify_property_list_changed(); } bool Decal::is_distance_fade_enabled() const { @@ -154,6 +154,12 @@ Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const { return Vector<Face3>(); } +void Decal::_validate_property(PropertyInfo &property) const { + if (!distance_fade_enabled && (property.name == "distance_fade_begin" || property.name == "distance_fade_length")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void Decal::_bind_methods() { ClassDB::bind_method(D_METHOD("set_extents", "extents"), &Decal::set_extents); ClassDB::bind_method(D_METHOD("get_extents"), &Decal::get_extents); @@ -220,18 +226,6 @@ void Decal::_bind_methods() { } Decal::Decal() { - extents = Vector3(1, 1, 1); - emission_energy = 1.0; - modulate = Color(1, 1, 1, 1); - albedo_mix = 1.0; - cull_mask = (1 << 20) - 1; - upper_fade = 0.3; - lower_fade = 0.3; - normal_fade = 0; - distance_fade_enabled = false; - distance_fade_begin = 10; - distance_fade_length = 1; - decal = RenderingServer::get_singleton()->decal_create(); RS::get_singleton()->instance_set_base(get_instance(), decal); } diff --git a/scene/3d/decal.h b/scene/3d/decal.h index e821461772..ce19e76de1 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -49,21 +49,22 @@ public: private: RID decal; - Vector3 extents; + Vector3 extents = Vector3(1, 1, 1); Ref<Texture2D> textures[TEXTURE_MAX]; - float emission_energy; - float albedo_mix; - Color modulate; - uint32_t cull_mask; - float normal_fade; - float upper_fade; - float lower_fade; - bool distance_fade_enabled; - float distance_fade_begin; - float distance_fade_length; + float emission_energy = 1.0; + float albedo_mix = 1.0; + Color modulate = Color(1, 1, 1, 1); + uint32_t cull_mask = (1 << 20) - 1; + float normal_fade = 0.0; + float upper_fade = 0.3; + float lower_fade = 0.3; + bool distance_fade_enabled = false; + float distance_fade_begin = 10.0; + float distance_fade_length = 1.0; protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: void set_extents(const Vector3 &p_extents); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index fd592012f8..43f820e5d4 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -91,7 +91,7 @@ Dictionary GIProbeData::_get_data() const { } void GIProbeData::allocate(const Transform &p_to_cell_xform, const AABB &p_aabb, const Vector3 &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { - RS::get_singleton()->gi_probe_allocate(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); + RS::get_singleton()->gi_probe_allocate_data(probe, p_to_cell_xform, p_aabb, p_octree_size, p_octree_cells, p_data_cells, p_distance_field, p_level_counts); bounds = p_aabb; to_cell_xform = p_to_cell_xform; octree_size = p_octree_size; @@ -221,7 +221,7 @@ RID GIProbeData::get_rid() const { void GIProbeData::_validate_property(PropertyInfo &property) const { if (property.name == "anisotropy_strength") { - bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/quality/gi_probes/anisotropic"); + bool anisotropy_enabled = ProjectSettings::get_singleton()->get("rendering/global_illumination/gi_probes/anisotropic"); if (!anisotropy_enabled) { property.usage = PROPERTY_USAGE_NOEDITOR; } @@ -286,17 +286,6 @@ void GIProbeData::_bind_methods() { } GIProbeData::GIProbeData() { - ao = 0.0; - ao_size = 0.5; - dynamic_range = 4; - energy = 1.0; - bias = 1.5; - normal_bias = 0.0; - propagation = 0.7; - anisotropy_strength = 0.5; - interior = false; - use_two_bounces = false; - probe = RS::get_singleton()->gi_probe_create(); } @@ -334,7 +323,6 @@ GIProbe::Subdiv GIProbe::get_subdiv() const { void GIProbe::set_extents(const Vector3 &p_extents) { extents = p_extents; update_gizmo(); - _change_notify("extents"); } Vector3 GIProbe::get_extents() const { @@ -427,13 +415,16 @@ Vector3i GIProbe::get_estimated_cell_size() const { void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { static const int subdiv_value[SUBDIV_MAX] = { 6, 7, 8, 9 }; + p_from_node = p_from_node ? p_from_node : get_parent(); + ERR_FAIL_NULL(p_from_node); + Voxelizer baker; baker.begin_bake(subdiv_value[subdiv], AABB(-extents, extents * 2.0)); List<PlotMesh> mesh_list; - _find_meshes(p_from_node ? p_from_node : get_parent(), mesh_list); + _find_meshes(p_from_node, mesh_list); if (bake_begin_function) { bake_begin_function(mesh_list.size() + 1); @@ -497,7 +488,7 @@ void GIProbe::bake(Node *p_from_node, bool p_create_visual_debug) { bake_end_function(); } - _change_notify(); //bake property may have changed + notify_property_list_changed(); //bake property may have changed } void GIProbe::_debug_bake() { @@ -516,11 +507,14 @@ String GIProbe::get_configuration_warning() const { String warning = VisualInstance3D::get_configuration_warning(); if (RenderingServer::get_singleton()->is_low_end()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("GIProbes are not supported by the GLES2 video driver.\nUse a BakedLightmap instead."); + } else if (probe_data.is_null()) { + warning += TTR("No GIProbe data set, so this node is disabled. Bake static objects to enable GI."); } + return warning; } @@ -550,9 +544,6 @@ void GIProbe::_bind_methods() { } GIProbe::GIProbe() { - subdiv = SUBDIV_128; - extents = Vector3(10, 10, 10); - gi_probe = RS::get_singleton()->gi_probe_create(); set_disable_scale(true); } diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h index 2dadf48a06..534b425557 100644 --- a/scene/3d/gi_probe.h +++ b/scene/3d/gi_probe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,16 +46,16 @@ class GIProbeData : public Resource { AABB bounds; Vector3 octree_size; - float dynamic_range; - float energy; - float bias; - float normal_bias; - float propagation; - float anisotropy_strength; - float ao; - float ao_size; - bool interior; - bool use_two_bounces; + float dynamic_range = 4.0; + float energy = 1.0; + float bias = 1.5; + float normal_bias = 0.0; + float propagation = 0.7; + float anisotropy_strength = 0.5; + float ao = 0.0; + float ao_size = 0.5; + bool interior = false; + bool use_two_bounces = false; protected: static void _bind_methods(); @@ -129,8 +129,8 @@ private: RID gi_probe; - Subdiv subdiv; - Vector3 extents; + Subdiv subdiv = SUBDIV_128; + Vector3 extents = Vector3(10, 10, 10); struct PlotMesh { Ref<Material> override_material; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index ec33d7bcab..e2cfc2ed87 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -100,7 +100,6 @@ void GPUParticles3D::set_visibility_aabb(const AABB &p_aabb) { visibility_aabb = p_aabb; RS::get_singleton()->particles_set_custom_aabb(particles, visibility_aabb); update_gizmo(); - _change_notify("visibility_aabb"); } void GPUParticles3D::set_use_local_coordinates(bool p_enable) { @@ -190,7 +189,7 @@ void GPUParticles3D::set_draw_passes(int p_count) { ERR_FAIL_COND(p_count < 1); draw_passes.resize(p_count); RS::get_singleton()->particles_set_draw_passes(particles, p_count); - _change_notify(); + notify_property_list_changed(); } int GPUParticles3D::get_draw_passes() const { @@ -349,11 +348,11 @@ void GPUParticles3D::_notification(int p_what) { } } - // Use internal process when emitting and one_shot are on so that when + // Use internal process when emitting and one_shot is on so that when // the shot ends the editor can properly update if (p_what == NOTIFICATION_INTERNAL_PROCESS) { if (one_shot && !is_emitting()) { - _change_notify(); + notify_property_list_changed(); set_process_internal(false); } } diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h index f0e5f05e5b..0c1a1a510c 100644 --- a/scene/3d/gpu_particles_3d.h +++ b/scene/3d/gpu_particles_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index 1f0d5d587d..97241be60f 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -293,11 +293,11 @@ void GPUParticlesCollisionSDF::_find_closest_distance(const Vector3 &p_pos, cons SGN(cb.cross(nor).dot(pb)) + SGN(ac.cross(nor).dot(pc)) < 2.0) ? - MIN(MIN( + 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)); + nor.dot(pa) * nor.dot(pa) / Vector3_dot2(nor)); closest_distance = MIN(closest_distance, inside_d); } diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h index 9b644ade6b..81c33663f3 100644 --- a/scene/3d/gpu_particles_collision_3d.h +++ b/scene/3d/gpu_particles_collision_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -130,16 +130,16 @@ private: LEAF_MASK = LEAF_BIT - 1 }; AABB bounds; - uint32_t children[2]; + uint32_t children[2] = {}; }; struct FacePos { Vector3 center; - uint32_t index; + uint32_t index = 0; }; struct FaceSort { - uint32_t axis; + uint32_t axis = 0; bool operator()(const FacePos &p_left, const FacePos &p_right) const { return p_left.center[axis] < p_right.center[axis]; } @@ -148,13 +148,13 @@ private: 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; + float *cells = nullptr; Vector3i size; - float cell_size; + float cell_size = 0.0; Vector3 cell_offset; - const BVH *bvh; - const Face3 *triangles; - float thickness; + const BVH *bvh = nullptr; + const Face3 *triangles = nullptr; + float thickness = 0.0; }; void _find_closest_distance(const Vector3 &p_pos, const BVH *bvh, uint32_t p_bvh_cell, const Face3 *triangles, float thickness, float &closest_distance); diff --git a/scene/3d/immediate_geometry_3d.cpp b/scene/3d/immediate_geometry_3d.cpp index 7ccfd527a1..d64babaa9d 100644 --- a/scene/3d/immediate_geometry_3d.cpp +++ b/scene/3d/immediate_geometry_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -87,21 +87,24 @@ Vector<Face3> ImmediateGeometry3D::get_faces(uint32_t p_usage_flags) const { } void ImmediateGeometry3D::add_sphere(int p_lats, int p_lons, float p_radius, bool p_add_uv) { + const double lat_step = Math_TAU / p_lats; + const double lon_step = Math_TAU / p_lons; + for (int i = 1; i <= p_lats; i++) { - double lat0 = Math_PI * (-0.5 + (double)(i - 1) / p_lats); + double lat0 = lat_step * (i - 1) - Math_TAU / 4; double z0 = Math::sin(lat0); double zr0 = Math::cos(lat0); - double lat1 = Math_PI * (-0.5 + (double)i / p_lats); + double lat1 = lat_step * i - Math_TAU / 4; double z1 = Math::sin(lat1); double zr1 = Math::cos(lat1); for (int j = p_lons; j >= 1; j--) { - double lng0 = 2 * Math_PI * (double)(j - 1) / p_lons; + double lng0 = lon_step * (j - 1); double x0 = Math::cos(lng0); double y0 = Math::sin(lng0); - double lng1 = 2 * Math_PI * (double)(j) / p_lons; + double lng1 = lon_step * j; double x1 = Math::cos(lng1); double y1 = Math::sin(lng1); @@ -147,7 +150,6 @@ void ImmediateGeometry3D::_bind_methods() { ImmediateGeometry3D::ImmediateGeometry3D() { im = RenderingServer::get_singleton()->immediate_create(); set_base(im); - empty = true; } ImmediateGeometry3D::~ImmediateGeometry3D() { diff --git a/scene/3d/immediate_geometry_3d.h b/scene/3d/immediate_geometry_3d.h index 1403936e22..ee4938d9f7 100644 --- a/scene/3d/immediate_geometry_3d.h +++ b/scene/3d/immediate_geometry_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,7 +41,7 @@ class ImmediateGeometry3D : public GeometryInstance3D { //a list of textures drawn need to be kept, to avoid references // in RenderingServer from becoming invalid if the texture is no longer used List<Ref<Texture2D>> cached_textures; - bool empty; + bool empty = true; AABB aabb; protected: diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index 3f816535f5..f109640aef 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,11 +48,7 @@ void Light3D::set_param(Param p_param, float p_value) { update_gizmo(); if (p_param == PARAM_SPOT_ANGLE) { - _change_notify("spot_angle"); update_configuration_warning(); - } else if (p_param == PARAM_RANGE) { - _change_notify("omni_range"); - _change_notify("spot_range"); } } } @@ -69,6 +65,8 @@ void Light3D::set_shadow(bool p_enable) { if (type == RenderingServer::LIGHT_SPOT || type == RenderingServer::LIGHT_OMNI) { update_configuration_warning(); } + + notify_property_list_changed(); } bool Light3D::has_shadow() const { @@ -184,8 +182,6 @@ void Light3D::_update_visibility() { #endif RS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree() && editor_ok); - - _change_notify("geometry/visible"); } void Light3D::_notification(int p_what) { @@ -208,10 +204,18 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &property) const { + if (!shadow && (property.name == "shadow_color" || property.name == "shadow_bias" || property.name == "shadow_normal_bias" || property.name == "shadow_reverse_cull_face" || property.name == "shadow_transmittance_bias" || property.name == "shadow_fog_fade" || property.name == "shadow_blur")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") { property.usage = 0; } + if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_specular") { + property.usage = 0; + } + if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_projector") { property.usage = 0; } @@ -257,7 +261,7 @@ void Light3D::_bind_methods() { ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_projector", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_projector", "get_projector"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,64,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_size", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_angular_distance", PROPERTY_HINT_RANGE, "0,90,0.01"), "set_param", "get_param", PARAM_SIZE); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative"); ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR); @@ -320,10 +324,6 @@ Light3D::Light3D(RenderingServer::LightType p_type) { RS::get_singleton()->instance_set_base(get_instance(), light); - reverse_cull = false; - bake_mode = BAKE_DYNAMIC; - - editor_only = false; set_color(Color(1, 1, 1, 1)); set_shadow(false); set_negative(false); @@ -347,13 +347,12 @@ 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_VOLUMETRIC_FOG_FADE, 0.1); set_param(PARAM_SHADOW_FADE_START, 1); set_disable_scale(true); } Light3D::Light3D() { - type = RenderingServer::LIGHT_DIRECTIONAL; ERR_PRINT("Light3D should not be instanced directly; use the DirectionalLight3D, OmniLight3D or SpotLight3D subtypes instead."); } @@ -462,7 +461,7 @@ String OmniLight3D::get_configuration_warning() const { String warning = Light3D::get_configuration_warning(); if (!has_shadow() && get_projector().is_valid()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("Projector texture only works with shadows active."); @@ -496,14 +495,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.empty()) { + if (!warning.is_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.empty()) { + if (!warning.is_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 08287a3313..311db54bce 100644 --- a/scene/3d/light_3d.h +++ b/scene/3d/light_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,16 +71,16 @@ public: private: Color color; - float param[PARAM_MAX]; + float param[PARAM_MAX] = {}; Color shadow_color; - bool shadow; - bool negative; - bool reverse_cull; - uint32_t cull_mask; - RS::LightType type; - bool editor_only; + bool shadow = false; + bool negative = false; + bool reverse_cull = false; + uint32_t cull_mask = 0; + RS::LightType type = RenderingServer::LIGHT_DIRECTIONAL; + bool editor_only = false; void _update_visibility(); - BakeMode bake_mode; + BakeMode bake_mode = BAKE_DYNAMIC; Ref<Texture2D> projector; // bind helpers diff --git a/scene/3d/lightmap_probe.cpp b/scene/3d/lightmap_probe.cpp index ee21934b80..830b97ffab 100644 --- a/scene/3d/lightmap_probe.cpp +++ b/scene/3d/lightmap_probe.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/lightmap_probe.h b/scene/3d/lightmap_probe.h index c4bd33556f..df87ed49dd 100644 --- a/scene/3d/lightmap_probe.h +++ b/scene/3d/lightmap_probe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/lightmapper.cpp b/scene/3d/lightmapper.cpp index 26faf5154c..c17ac52aa2 100644 --- a/scene/3d/lightmapper.cpp +++ b/scene/3d/lightmapper.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/lightmapper.h b/scene/3d/lightmapper.h index ccf9bde279..a07a964c01 100644 --- a/scene/3d/lightmapper.h +++ b/scene/3d/lightmapper.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/listener_3d.cpp b/scene/3d/listener_3d.cpp index 0a5b9ad09f..9842f152d7 100644 --- a/scene/3d/listener_3d.cpp +++ b/scene/3d/listener_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -159,8 +159,6 @@ void Listener3D::_bind_methods() { } Listener3D::Listener3D() { - current = false; - force_change = false; set_notify_transform(true); //active=false; } diff --git a/scene/3d/listener_3d.h b/scene/3d/listener_3d.h index 4b6923d6e8..85657a8e53 100644 --- a/scene/3d/listener_3d.h +++ b/scene/3d/listener_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,8 +38,8 @@ class Listener3D : public Node3D { GDCLASS(Listener3D, Node3D); private: - bool force_change; - bool current; + bool force_change = false; + bool current = false; RID scenario_id; diff --git a/scene/3d/mesh_instance_3d.cpp b/scene/3d/mesh_instance_3d.cpp index 13f40aed4f..b997c64b29 100644 --- a/scene/3d/mesh_instance_3d.cpp +++ b/scene/3d/mesh_instance_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -95,7 +95,7 @@ void MeshInstance3D::_get_property_list(List<PropertyInfo> *p_list) const { ls.sort(); for (List<String>::Element *E = ls.front(); E; E = E->next()) { - p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001")); + p_list->push_back(PropertyInfo(Variant::FLOAT, E->get(), PROPERTY_HINT_RANGE, "-1,1,0.00001")); } if (mesh.is_valid()) { @@ -112,7 +112,6 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) { if (mesh.is_valid()) { mesh->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &MeshInstance3D::_mesh_changed)); - materials.clear(); } mesh = p_mesh; @@ -136,7 +135,7 @@ void MeshInstance3D::set_mesh(const Ref<Mesh> &p_mesh) { update_gizmo(); - _change_notify(); + notify_property_list_changed(); } Ref<Mesh> MeshInstance3D::get_mesh() const { @@ -153,7 +152,7 @@ void MeshInstance3D::_resolve_skeleton_path() { if (skin_internal.is_null()) { //a skin was created for us skin_internal = new_skin_reference->get_skin(); - _change_notify(); + notify_property_list_changed(); } } } @@ -320,6 +319,7 @@ Ref<Material> MeshInstance3D::get_active_material(int p_surface) const { } void MeshInstance3D::_mesh_changed() { + ERR_FAIL_COND(mesh.is_null()); materials.resize(mesh->get_surface_count()); } @@ -429,7 +429,6 @@ void MeshInstance3D::_bind_methods() { } MeshInstance3D::MeshInstance3D() { - skeleton_path = NodePath(".."); } MeshInstance3D::~MeshInstance3D() { diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 4434e305e8..eb300784b1 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,15 +44,11 @@ protected: Ref<Skin> skin; Ref<Skin> skin_internal; Ref<SkinReference> skin_ref; - NodePath skeleton_path; + NodePath skeleton_path = NodePath(".."); struct BlendShapeTrack { - int idx; - float value; - BlendShapeTrack() { - idx = 0; - value = 0; - } + int idx = 0; + float value = 0.0; }; Map<StringName, BlendShapeTrack> blend_shape_tracks; diff --git a/scene/3d/multimesh_instance_3d.cpp b/scene/3d/multimesh_instance_3d.cpp index 88dff111f7..2adef115cf 100644 --- a/scene/3d/multimesh_instance_3d.cpp +++ b/scene/3d/multimesh_instance_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/multimesh_instance_3d.h b/scene/3d/multimesh_instance_3d.h index 6e075b7f7f..63735fd3a6 100644 --- a/scene/3d/multimesh_instance_3d.h +++ b/scene/3d/multimesh_instance_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/navigation_3d.cpp b/scene/3d/navigation_3d.cpp deleted file mode 100644 index 851966db2b..0000000000 --- a/scene/3d/navigation_3d.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************/ -/* navigation_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 "navigation_3d.h" - -#include "servers/navigation_server_3d.h" - -Vector<Vector3> Navigation3D::get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize) const { - return NavigationServer3D::get_singleton()->map_get_path(map, p_start, p_end, p_optimize); -} - -Vector3 Navigation3D::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const { - return NavigationServer3D::get_singleton()->map_get_closest_point_to_segment(map, p_from, p_to, p_use_collision); -} - -Vector3 Navigation3D::get_closest_point(const Vector3 &p_point) const { - return NavigationServer3D::get_singleton()->map_get_closest_point(map, p_point); -} - -Vector3 Navigation3D::get_closest_point_normal(const Vector3 &p_point) const { - return NavigationServer3D::get_singleton()->map_get_closest_point_normal(map, p_point); -} - -RID Navigation3D::get_closest_point_owner(const Vector3 &p_point) const { - return NavigationServer3D::get_singleton()->map_get_closest_point_owner(map, p_point); -} - -void Navigation3D::set_up_vector(const Vector3 &p_up) { - up = p_up; - NavigationServer3D::get_singleton()->map_set_up(map, up); -} - -Vector3 Navigation3D::get_up_vector() const { - return up; -} - -void Navigation3D::set_cell_size(float p_cell_size) { - cell_size = p_cell_size; - NavigationServer3D::get_singleton()->map_set_cell_size(map, cell_size); -} - -void Navigation3D::set_edge_connection_margin(float p_edge_connection_margin) { - edge_connection_margin = p_edge_connection_margin; - NavigationServer3D::get_singleton()->map_set_edge_connection_margin(map, edge_connection_margin); -} - -void Navigation3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_rid"), &Navigation3D::get_rid); - - ClassDB::bind_method(D_METHOD("get_simple_path", "start", "end", "optimize"), &Navigation3D::get_simple_path, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_closest_point_to_segment", "start", "end", "use_collision"), &Navigation3D::get_closest_point_to_segment, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Navigation3D::get_closest_point); - ClassDB::bind_method(D_METHOD("get_closest_point_normal", "to_point"), &Navigation3D::get_closest_point_normal); - ClassDB::bind_method(D_METHOD("get_closest_point_owner", "to_point"), &Navigation3D::get_closest_point_owner); - - ClassDB::bind_method(D_METHOD("set_up_vector", "up"), &Navigation3D::set_up_vector); - ClassDB::bind_method(D_METHOD("get_up_vector"), &Navigation3D::get_up_vector); - - ClassDB::bind_method(D_METHOD("set_cell_size", "cell_size"), &Navigation3D::set_cell_size); - ClassDB::bind_method(D_METHOD("get_cell_size"), &Navigation3D::get_cell_size); - - ClassDB::bind_method(D_METHOD("set_edge_connection_margin", "margin"), &Navigation3D::set_edge_connection_margin); - ClassDB::bind_method(D_METHOD("get_edge_connection_margin"), &Navigation3D::get_edge_connection_margin); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "up_vector"), "set_up_vector", "get_up_vector"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cell_size"), "set_cell_size", "get_cell_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_connection_margin"), "set_edge_connection_margin", "get_edge_connection_margin"); -} - -void Navigation3D::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: { - NavigationServer3D::get_singleton()->map_set_active(map, true); - } break; - case NOTIFICATION_EXIT_TREE: { - NavigationServer3D::get_singleton()->map_set_active(map, false); - } break; - } -} - -Navigation3D::Navigation3D() { - map = NavigationServer3D::get_singleton()->map_create(); - - set_cell_size(0.3); - set_edge_connection_margin(5.0); // Five meters, depends a lot on the agent's radius - - up = Vector3(0, 1, 0); -} - -Navigation3D::~Navigation3D() { - NavigationServer3D::get_singleton()->free(map); -} diff --git a/scene/3d/navigation_3d.h b/scene/3d/navigation_3d.h deleted file mode 100644 index 890caed171..0000000000 --- a/scene/3d/navigation_3d.h +++ /dev/null @@ -1,78 +0,0 @@ -/*************************************************************************/ -/* navigation_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 NAVIGATION_3D_H -#define NAVIGATION_3D_H - -#include "scene/3d/navigation_region_3d.h" -#include "scene/3d/node_3d.h" - -class Navigation3D : public Node3D { - GDCLASS(Navigation3D, Node3D); - - RID map; - - Vector3 up; - real_t cell_size; - real_t edge_connection_margin; - -protected: - static void _bind_methods(); - void _notification(int p_what); - -public: - RID get_rid() const { - return map; - } - - void set_up_vector(const Vector3 &p_up); - Vector3 get_up_vector() const; - - void set_cell_size(float p_cell_size); - float get_cell_size() const { - return cell_size; - } - - void set_edge_connection_margin(float p_edge_connection_margin); - float get_edge_connection_margin() const { - return edge_connection_margin; - } - - Vector<Vector3> get_simple_path(const Vector3 &p_start, const Vector3 &p_end, bool p_optimize = true) const; - Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const; - Vector3 get_closest_point(const Vector3 &p_point) const; - Vector3 get_closest_point_normal(const Vector3 &p_point) const; - RID get_closest_point_owner(const Vector3 &p_point) const; - - Navigation3D(); - ~Navigation3D(); -}; - -#endif // NAVIGATION_H diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index f9f8f276a3..21ca3d70dd 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,7 +31,6 @@ #include "navigation_agent_3d.h" #include "core/config/engine.h" -#include "scene/3d/navigation_3d.h" #include "servers/navigation_server_3d.h" void NavigationAgent3D::_bind_methods() { @@ -47,9 +46,6 @@ void NavigationAgent3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_ignore_y", "ignore"), &NavigationAgent3D::set_ignore_y); ClassDB::bind_method(D_METHOD("get_ignore_y"), &NavigationAgent3D::get_ignore_y); - ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationAgent3D::set_navigation_node); - ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationAgent3D::get_navigation_node); - ClassDB::bind_method(D_METHOD("set_neighbor_dist", "neighbor_dist"), &NavigationAgent3D::set_neighbor_dist); ClassDB::bind_method(D_METHOD("get_neighbor_dist"), &NavigationAgent3D::get_neighbor_dist); @@ -101,28 +97,10 @@ void NavigationAgent3D::_notification(int p_what) { agent_parent = Object::cast_to<Node3D>(get_parent()); NavigationServer3D::get_singleton()->agent_set_callback(agent, this, "_avoidance_done"); - - // Search the navigation node and set it - { - Navigation3D *nav = nullptr; - Node *p = get_parent(); - while (p != nullptr) { - nav = Object::cast_to<Navigation3D>(p); - if (nav != nullptr) { - p = nullptr; - } else { - p = p->get_parent(); - } - } - - set_navigation(nav); - } - set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { agent_parent = nullptr; - set_navigation(nullptr); set_physics_process_internal(false); } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -154,25 +132,6 @@ NavigationAgent3D::~NavigationAgent3D() { agent = RID(); // Pointless } -void NavigationAgent3D::set_navigation(Navigation3D *p_nav) { - if (navigation == p_nav) { - return; // Pointless - } - - navigation = p_nav; - NavigationServer3D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); -} - -void NavigationAgent3D::set_navigation_node(Node *p_nav) { - Navigation3D *nav = Object::cast_to<Navigation3D>(p_nav); - ERR_FAIL_COND(nav == nullptr); - set_navigation(nav); -} - -Node *NavigationAgent3D::get_navigation_node() const { - return Object::cast_to<Node>(navigation); -} - void NavigationAgent3D::set_target_desired_distance(real_t p_dd) { target_desired_distance = p_dd; } @@ -290,7 +249,7 @@ String NavigationAgent3D::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!Object::cast_to<Node3D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The NavigationAgent3D can be used only under a spatial node."); @@ -303,7 +262,7 @@ void NavigationAgent3D::update_navigation() { if (agent_parent == nullptr) { return; } - if (navigation == nullptr) { + if (!agent_parent->is_inside_tree()) { return; } if (update_frame_id == Engine::get_singleton()->get_physics_frames()) { @@ -337,7 +296,7 @@ void NavigationAgent3D::update_navigation() { } if (reload_path) { - navigation_path = NavigationServer3D::get_singleton()->map_get_path(navigation->get_rid(), o, target_location, true); + navigation_path = NavigationServer3D::get_singleton()->map_get_path(agent_parent->get_world_3d()->get_navigation_map(), o, target_location, true); navigation_finished = false; nav_path_index = 0; emit_signal("path_changed"); diff --git a/scene/3d/navigation_agent_3d.h b/scene/3d/navigation_agent_3d.h index dcfd302561..22db889618 100644 --- a/scene/3d/navigation_agent_3d.h +++ b/scene/3d/navigation_agent_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,13 +35,11 @@ #include "scene/main/node.h" class Node3D; -class Navigation3D; class NavigationAgent3D : public Node { GDCLASS(NavigationAgent3D, Node); Node3D *agent_parent = nullptr; - Navigation3D *navigation = nullptr; RID agent; @@ -76,14 +74,6 @@ public: NavigationAgent3D(); virtual ~NavigationAgent3D(); - void set_navigation(Navigation3D *p_nav); - const Navigation3D *get_navigation() const { - return navigation; - } - - void set_navigation_node(Node *p_nav); - Node *get_navigation_node() const; - RID get_rid() const { return agent; } diff --git a/scene/3d/navigation_obstacle_3d.cpp b/scene/3d/navigation_obstacle_3d.cpp index adbff06ed6..df03bca4fd 100644 --- a/scene/3d/navigation_obstacle_3d.cpp +++ b/scene/3d/navigation_obstacle_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,55 +31,38 @@ #include "navigation_obstacle_3d.h" #include "scene/3d/collision_shape_3d.h" -#include "scene/3d/navigation_3d.h" #include "scene/3d/physics_body_3d.h" #include "servers/navigation_server_3d.h" void NavigationObstacle3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_navigation", "navigation"), &NavigationObstacle3D::set_navigation_node); - ClassDB::bind_method(D_METHOD("get_navigation"), &NavigationObstacle3D::get_navigation_node); } void NavigationObstacle3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { - update_agent_shape(); - - // Search the navigation node and set it - { - Navigation3D *nav = nullptr; - Node *p = get_parent(); - while (p != nullptr) { - nav = Object::cast_to<Navigation3D>(p); - if (nav != nullptr) { - p = nullptr; - } else { - p = p->get_parent(); - } - } - - set_navigation(nav); - } - set_physics_process_internal(true); } break; case NOTIFICATION_EXIT_TREE: { - set_navigation(nullptr); set_physics_process_internal(false); } break; + case NOTIFICATION_PARENTED: { + parent_node3d = Object::cast_to<Node3D>(get_parent()); + update_agent_shape(); + } break; + case NOTIFICATION_UNPARENTED: { + parent_node3d = nullptr; + } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - Node3D *spatial = Object::cast_to<Node3D>(get_parent()); - if (spatial) { - NavigationServer3D::get_singleton()->agent_set_position(agent, spatial->get_global_transform().origin); - } - - PhysicsBody3D *rigid = Object::cast_to<PhysicsBody3D>(get_parent()); - if (rigid) { - Vector3 v = rigid->get_linear_velocity(); - NavigationServer3D::get_singleton()->agent_set_velocity(agent, v); - NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, v); + if (parent_node3d) { + NavigationServer3D::get_singleton()->agent_set_position(agent, parent_node3d->get_global_transform().origin); + + PhysicsBody3D *rigid = Object::cast_to<PhysicsBody3D>(get_parent()); + if (rigid) { + Vector3 v = rigid->get_linear_velocity(); + NavigationServer3D::get_singleton()->agent_set_velocity(agent, v); + NavigationServer3D::get_singleton()->agent_set_target_velocity(agent, v); + } } - } break; } } @@ -93,30 +76,11 @@ NavigationObstacle3D::~NavigationObstacle3D() { agent = RID(); // Pointless } -void NavigationObstacle3D::set_navigation(Navigation3D *p_nav) { - if (navigation == p_nav) { - return; // Pointless - } - - navigation = p_nav; - NavigationServer3D::get_singleton()->agent_set_map(agent, navigation == nullptr ? RID() : navigation->get_rid()); -} - -void NavigationObstacle3D::set_navigation_node(Node *p_nav) { - Navigation3D *nav = Object::cast_to<Navigation3D>(p_nav); - ERR_FAIL_COND(nav == nullptr); - set_navigation(nav); -} - -Node *NavigationObstacle3D::get_navigation_node() const { - return Object::cast_to<Node>(navigation); -} - String NavigationObstacle3D::get_configuration_warning() const { String warning = Node::get_configuration_warning(); - if (!Object::cast_to<Node3D>(get_parent())) { - if (!warning.empty()) { + if (!parent_node3d) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The NavigationObstacle3D only serves to provide collision avoidance to a spatial object."); @@ -126,40 +90,38 @@ String NavigationObstacle3D::get_configuration_warning() const { } void NavigationObstacle3D::update_agent_shape() { - Node *node = get_parent(); - - // Estimate the radius of this physics body - real_t radius = 0.0; - for (int i(0); i < node->get_child_count(); i++) { - // For each collision shape - CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(node->get_child(i)); - if (cs) { - // Take the distance between the Body center to the shape center - real_t r = cs->get_transform().origin.length(); - if (cs->get_shape().is_valid()) { - // and add the enclosing shape radius - r += cs->get_shape()->get_enclosing_radius(); + if (parent_node3d) { + // Estimate the radius of this physics body + real_t radius = 0.0; + for (int i(0); i < parent_node3d->get_child_count(); i++) { + // For each collision shape + CollisionShape3D *cs = Object::cast_to<CollisionShape3D>(parent_node3d->get_child(i)); + if (cs) { + // Take the distance between the Body center to the shape center + real_t r = cs->get_transform().origin.length(); + if (cs->get_shape().is_valid()) { + // and add the enclosing shape radius + r += cs->get_shape()->get_enclosing_radius(); + } + Vector3 s = cs->get_global_transform().basis.get_scale(); + r *= MAX(s.x, MAX(s.y, s.z)); + // Takes the biggest radius + radius = MAX(radius, r); } - Vector3 s = cs->get_global_transform().basis.get_scale(); - r *= MAX(s.x, MAX(s.y, s.z)); - // Takes the biggest radius - radius = MAX(radius, r); } - } - Node3D *spa = Object::cast_to<Node3D>(node); - if (spa) { - Vector3 s = spa->get_global_transform().basis.get_scale(); + + Vector3 s = parent_node3d->get_global_transform().basis.get_scale(); radius *= MAX(s.x, MAX(s.y, s.z)); - } - if (radius == 0.0) { - radius = 1.0; // Never a 0 radius - } + if (radius == 0.0) { + radius = 1.0; // Never a 0 radius + } - // Initialize the Agent as an object - NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0); - NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0); - NavigationServer3D::get_singleton()->agent_set_radius(agent, radius); - NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0); + // Initialize the Agent as an object + NavigationServer3D::get_singleton()->agent_set_neighbor_dist(agent, 0.0); + NavigationServer3D::get_singleton()->agent_set_max_neighbors(agent, 0); + NavigationServer3D::get_singleton()->agent_set_time_horizon(agent, 0.0); + NavigationServer3D::get_singleton()->agent_set_radius(agent, radius); + NavigationServer3D::get_singleton()->agent_set_max_speed(agent, 0.0); + } } diff --git a/scene/3d/navigation_obstacle_3d.h b/scene/3d/navigation_obstacle_3d.h index f2dc9182ca..b1bb53724a 100644 --- a/scene/3d/navigation_obstacle_3d.h +++ b/scene/3d/navigation_obstacle_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,15 +31,13 @@ #ifndef NAVIGATION_OBSTACLE_H #define NAVIGATION_OBSTACLE_H +#include "scene/3d/node_3d.h" #include "scene/main/node.h" -class Navigation3D; - class NavigationObstacle3D : public Node { GDCLASS(NavigationObstacle3D, Node); - Navigation3D *navigation = nullptr; - + Node3D *parent_node3d = nullptr; RID agent; protected: @@ -50,14 +48,6 @@ public: NavigationObstacle3D(); virtual ~NavigationObstacle3D(); - void set_navigation(Navigation3D *p_nav); - const Navigation3D *get_navigation() const { - return navigation; - } - - void set_navigation_node(Node *p_nav); - Node *get_navigation_node() const; - RID get_rid() const { return agent; } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 2ae01c7ab8..3ca704e4b8 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,7 +32,6 @@ #include "core/os/thread.h" #include "mesh_instance_3d.h" -#include "navigation_3d.h" #include "servers/navigation_server_3d.h" void NavigationRegion3D::set_enabled(bool p_enabled) { @@ -48,9 +47,7 @@ void NavigationRegion3D::set_enabled(bool p_enabled) { if (!enabled) { NavigationServer3D::get_singleton()->region_set_map(region, RID()); } else { - if (navigation) { - NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid()); - } + NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); } if (debug_view) { @@ -69,22 +66,21 @@ bool NavigationRegion3D::is_enabled() const { return enabled; } +void NavigationRegion3D::set_layers(uint32_t p_layers) { + NavigationServer3D::get_singleton()->region_set_layers(region, p_layers); +} + +uint32_t NavigationRegion3D::get_layers() const { + return NavigationServer3D::get_singleton()->region_get_layers(region); +} + ///////////////////////////// void NavigationRegion3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - Node3D *c = this; - while (c) { - navigation = Object::cast_to<Navigation3D>(c); - if (navigation) { - if (enabled) { - NavigationServer3D::get_singleton()->region_set_map(region, navigation->get_rid()); - } - break; - } - - c = c->get_parent_spatial(); + if (enabled) { + NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map()); } if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { @@ -105,15 +101,12 @@ void NavigationRegion3D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { - if (navigation) { - NavigationServer3D::get_singleton()->region_set_map(region, RID()); - } + NavigationServer3D::get_singleton()->region_set_map(region, RID()); if (debug_view) { debug_view->queue_delete(); debug_view = nullptr; } - navigation = nullptr; } break; } } @@ -124,13 +117,13 @@ void NavigationRegion3D::set_navigation_mesh(const Ref<NavigationMesh> &p_navmes } if (navmesh.is_valid()) { - navmesh->remove_change_receptor(this); + navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } navmesh = p_navmesh; if (navmesh.is_valid()) { - navmesh->add_change_receptor(this); + navmesh->connect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } NavigationServer3D::get_singleton()->region_set_navmesh(region, p_navmesh); @@ -150,7 +143,7 @@ Ref<NavigationMesh> NavigationRegion3D::get_navigation_mesh() const { } struct BakeThreadsArgs { - NavigationRegion3D *nav_region; + NavigationRegion3D *nav_region = nullptr; }; void _bake_navigation_mesh(void *p_user_data) { @@ -170,18 +163,17 @@ void _bake_navigation_mesh(void *p_user_data) { } void NavigationRegion3D::bake_navigation_mesh() { - ERR_FAIL_COND(bake_thread != nullptr); + ERR_FAIL_COND(bake_thread.is_started()); BakeThreadsArgs *args = memnew(BakeThreadsArgs); args->nav_region = this; - bake_thread = Thread::create(_bake_navigation_mesh, args); - ERR_FAIL_COND(bake_thread == nullptr); + bake_thread.start(_bake_navigation_mesh, args); } void NavigationRegion3D::_bake_finished(Ref<NavigationMesh> p_nav_mesh) { set_navigation_mesh(p_nav_mesh); - bake_thread = nullptr; + bake_thread.wait_to_finish(); emit_signal("bake_finished"); } @@ -193,25 +185,13 @@ String NavigationRegion3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (!navmesh.is_valid()) { - if (!warning.empty()) { + if (!warning.is_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 warning; - } - - c = Object::cast_to<Node3D>(c->get_parent()); - } - - 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."); + return warning; } void NavigationRegion3D::_bind_methods() { @@ -221,17 +201,21 @@ void NavigationRegion3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &NavigationRegion3D::set_enabled); ClassDB::bind_method(D_METHOD("is_enabled"), &NavigationRegion3D::is_enabled); + ClassDB::bind_method(D_METHOD("set_layers", "layers"), &NavigationRegion3D::set_layers); + ClassDB::bind_method(D_METHOD("get_layers"), &NavigationRegion3D::get_layers); + ClassDB::bind_method(D_METHOD("bake_navigation_mesh"), &NavigationRegion3D::bake_navigation_mesh); ClassDB::bind_method(D_METHOD("_bake_finished", "nav_mesh"), &NavigationRegion3D::_bake_finished); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh"), "set_navigation_mesh", "get_navigation_mesh"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "layers", PROPERTY_HINT_LAYERS_3D_NAVIGATION), "set_layers", "get_layers"); ADD_SIGNAL(MethodInfo("navigation_mesh_changed")); ADD_SIGNAL(MethodInfo("bake_finished")); } -void NavigationRegion3D::_changed_callback(Object *p_changed, const char *p_prop) { +void NavigationRegion3D::_navigation_changed() { update_gizmo(); update_configuration_warning(); } @@ -243,7 +227,7 @@ NavigationRegion3D::NavigationRegion3D() { NavigationRegion3D::~NavigationRegion3D() { if (navmesh.is_valid()) { - navmesh->remove_change_receptor(this); + navmesh->disconnect("changed", callable_mp(this, &NavigationRegion3D::_navigation_changed)); } NavigationServer3D::get_singleton()->free(region); } diff --git a/scene/3d/navigation_region_3d.h b/scene/3d/navigation_region_3d.h index 4b1d59206b..52fa2d6159 100644 --- a/scene/3d/navigation_region_3d.h +++ b/scene/3d/navigation_region_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,8 +35,6 @@ #include "scene/resources/mesh.h" #include "scene/resources/navigation_mesh.h" -class Navigation3D; - class NavigationRegion3D : public Node3D { GDCLASS(NavigationRegion3D, Node3D); @@ -44,19 +42,22 @@ class NavigationRegion3D : public Node3D { RID region; Ref<NavigationMesh> navmesh; - Navigation3D *navigation = nullptr; Node *debug_view = nullptr; - Thread *bake_thread = nullptr; + Thread bake_thread; + + void _navigation_changed(); protected: void _notification(int p_what); static void _bind_methods(); - void _changed_callback(Object *p_changed, const char *p_prop) override; public: void set_enabled(bool p_enabled); bool is_enabled() const; + void set_layers(uint32_t p_layers); + uint32_t get_layers() const; + void set_navigation_mesh(const Ref<NavigationMesh> &p_navmesh); Ref<NavigationMesh> get_navigation_mesh() const; diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index deb04f0978..ba0f8cc870 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,7 +48,7 @@ a) If above is invalid, don't keep invalidating upwards 2) If a node sets a GLOBAL, it is converted to LOCAL (and forces validation of everything pending below) - drawback: setting/reading globals is useful and used very very often, and using affine inverses is slow + drawback: setting/reading globals is useful and used very often, and using affine inverses is slow --- @@ -226,10 +226,6 @@ void Node3D::_notification(int p_what) { void Node3D::set_transform(const Transform &p_transform) { data.local_transform = p_transform; data.dirty |= DIRTY_VECTORS; - _change_notify("translation"); - _change_notify("rotation"); - _change_notify("rotation_degrees"); - _change_notify("scale"); _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -239,8 +235,8 @@ void Node3D::set_transform(const Transform &p_transform) { void Node3D::set_global_transform(const Transform &p_transform) { Transform xform = (data.parent && !data.top_level_active) ? - data.parent->get_global_transform().affine_inverse() * p_transform : - p_transform; + data.parent->get_global_transform().affine_inverse() * p_transform : + p_transform; set_transform(xform); } @@ -307,7 +303,6 @@ Transform Node3D::get_relative_transform(const Node *p_parent) const { void Node3D::set_translation(const Vector3 &p_translation) { data.local_transform.origin = p_translation; - _change_notify("transform"); _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -322,7 +317,6 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) { data.rotation = p_euler_rad; data.dirty |= DIRTY_LOCAL; - _change_notify("transform"); _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -330,7 +324,7 @@ void Node3D::set_rotation(const Vector3 &p_euler_rad) { } void Node3D::set_rotation_degrees(const Vector3 &p_euler_deg) { - set_rotation(p_euler_deg * Math_PI / 180.0); + set_rotation(p_euler_deg * (Math_PI / 180.0)); } void Node3D::set_scale(const Vector3 &p_scale) { @@ -341,7 +335,6 @@ void Node3D::set_scale(const Vector3 &p_scale) { data.scale = p_scale; data.dirty |= DIRTY_LOCAL; - _change_notify("transform"); _propagate_transform_changed(this); if (data.notify_local_transform) { notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); @@ -364,7 +357,7 @@ Vector3 Node3D::get_rotation() const { } Vector3 Node3D::get_rotation_degrees() const { - return get_rotation() * 180.0 / Math_PI; + return get_rotation() * (180.0 / Math_PI); } Vector3 Node3D::get_scale() const { @@ -495,7 +488,6 @@ Ref<World3D> Node3D::get_world_3d() const { void Node3D::_propagate_visibility_changed() { notification(NOTIFICATION_VISIBILITY_CHANGED); emit_signal(SceneStringNames::get_singleton()->visibility_changed); - _change_notify("visible"); #ifdef TOOLS_ENABLED if (data.gizmo.is_valid()) { _update_gizmo(); @@ -755,8 +747,8 @@ void Node3D::_bind_methods() { ClassDB::bind_method(D_METHOD("orthonormalize"), &Node3D::orthonormalize); ClassDB::bind_method(D_METHOD("set_identity"), &Node3D::set_identity); - ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at); - ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position); + ClassDB::bind_method(D_METHOD("look_at", "target", "up"), &Node3D::look_at, DEFVAL(Vector3(0, 1, 0))); + ClassDB::bind_method(D_METHOD("look_at_from_position", "position", "target", "up"), &Node3D::look_at_from_position, DEFVAL(Vector3(0, 1, 0))); ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node3D::to_local); ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node3D::to_global); diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index 180c441a2a..a62c7b31a8 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -173,8 +173,8 @@ public: void global_scale(const Vector3 &p_scale); void global_translate(const Vector3 &p_offset); - void look_at(const Vector3 &p_target, const Vector3 &p_up); - void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up); + void look_at(const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); + void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up = Vector3(0, 1, 0)); Vector3 to_local(Vector3 p_global) const; Vector3 to_global(Vector3 p_local) const; diff --git a/scene/3d/path_3d.cpp b/scene/3d/path_3d.cpp index 54e6330722..7e2601902b 100644 --- a/scene/3d/path_3d.cpp +++ b/scene/3d/path_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -249,14 +249,14 @@ String PathFollow3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (!Object::cast_to<Path3D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_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) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("PathFollow3D's ROTATION_ORIENTED requires \"Up Vector\" to be enabled in its parent Path3D's Curve resource."); @@ -323,8 +323,6 @@ void PathFollow3D::set_offset(float p_offset) { _update_transform(); } - _change_notify("offset"); - _change_notify("unit_offset"); } void PathFollow3D::set_h_offset(float p_h_offset) { diff --git a/scene/3d/path_3d.h b/scene/3d/path_3d.h index 39f04f1556..17ee47593e 100644 --- a/scene/3d/path_3d.h +++ b/scene/3d/path_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -66,10 +66,10 @@ public: private: Path3D *path = nullptr; - real_t delta_offset = 0; // Change in offset since last _update_transform. - real_t offset = 0; - real_t h_offset = 0; - real_t v_offset = 0; + real_t delta_offset = 0.0; // Change in offset since last _update_transform. + real_t offset = 0.0; + real_t h_offset = 0.0; + real_t v_offset = 0.0; bool cubic = true; bool loop = true; RotationMode rotation_mode = ROTATION_XYZ; diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp index 15cd2238e1..e225c1f22d 100644 --- a/scene/3d/physics_body_3d.cpp +++ b/scene/3d/physics_body_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,7 +51,7 @@ Vector3 PhysicsBody3D::get_angular_velocity() const { return Vector3(); } -float PhysicsBody3D::get_inverse_mass() const { +real_t PhysicsBody3D::get_inverse_mass() const { return 0; } @@ -148,7 +148,8 @@ void PhysicsBody3D::_bind_methods() { } PhysicsBody3D::PhysicsBody3D(PhysicsServer3D::BodyMode p_mode) : - CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(p_mode), false) { + CollisionObject3D(PhysicsServer3D::get_singleton()->body_create(), false) { + PhysicsServer3D::get_singleton()->body_set_mode(get_rid(), p_mode); collision_layer = 1; collision_mask = 1; } @@ -311,7 +312,7 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap bool in_tree = E->get().in_tree; - if (E->get().shapes.empty()) { + if (E->get().shapes.is_empty()) { if (node) { node->disconnect(SceneStringNames::get_singleton()->tree_entered, callable_mp(this, &RigidBody3D::_body_enter_tree)); node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &RigidBody3D::_body_exit_tree)); @@ -330,8 +331,8 @@ void RigidBody3D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap struct _RigidBodyInOut { ObjectID id; - int shape; - int local_shape; + int shape = 0; + int local_shape = 0; }; void RigidBody3D::_direct_state_changed(Object *p_state) { @@ -415,13 +416,13 @@ void RigidBody3D::_direct_state_changed(Object *p_state) { } } - //process remotions + //process removals for (int i = 0; i < toremove_count; i++) { _body_inout(0, toremove[i].body_id, toremove[i].pair.body_shape, toremove[i].pair.local_shape); } - //process aditions + //process additions for (int i = 0; i < toadd_count; i++) { _body_inout(1, toadd[i].id, toadd[i].shape, toadd[i].local_shape); @@ -714,7 +715,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.empty()) { + if (!warning.is_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."); @@ -825,24 +826,6 @@ void RigidBody3D::_bind_methods() { RigidBody3D::RigidBody3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_RIGID) { - mode = MODE_RIGID; - - mass = 1; - max_contacts_reported = 0; - state = nullptr; - - gravity_scale = 1; - linear_damp = -1; - angular_damp = -1; - - //angular_velocity=0; - sleeping = false; - ccd = false; - - custom_integrator = false; - contact_monitor = nullptr; - can_sleep = true; - PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } @@ -924,7 +907,7 @@ bool KinematicBody3D::move_and_collide(const Vector3 &p_motion, bool p_infinite_ //so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 -Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { Vector3 body_velocity = p_linear_velocity; Vector3 body_velocity_normal = body_velocity.normalized(); Vector3 up_direction = p_up_direction.normalized(); @@ -1018,7 +1001,7 @@ Vector3 KinematicBody3D::move_and_slide(const Vector3 &p_linear_velocity, const return body_velocity; } -Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { +Vector3 KinematicBody3D::move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction, bool p_stop_on_slope, int p_max_slides, real_t p_floor_max_angle, bool p_infinite_inertia) { Vector3 up_direction = p_up_direction.normalized(); bool was_on_floor = on_floor; @@ -1090,7 +1073,7 @@ bool KinematicBody3D::separate_raycast_shapes(bool p_infinite_inertia, Collision Vector3 recover; int hits = PhysicsServer3D::get_singleton()->body_test_ray_separation(get_rid(), gt, p_infinite_inertia, recover, sep_res, 8, margin); int deepest = -1; - float deepest_depth; + real_t deepest_depth; for (int i = 0; i < hits; i++) { if (deepest == -1 || sep_res[i].collision_depth > deepest_depth) { deepest = i; @@ -1131,12 +1114,12 @@ bool KinematicBody3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { return PhysicsServer3D::get_singleton()->body_is_axis_locked(get_rid(), p_axis); } -void KinematicBody3D::set_safe_margin(float p_margin) { +void KinematicBody3D::set_safe_margin(real_t p_margin) { margin = p_margin; PhysicsServer3D::get_singleton()->body_set_kinematic_safe_margin(get_rid(), margin); } -float KinematicBody3D::get_safe_margin() const { +real_t KinematicBody3D::get_safe_margin() const { return margin; } @@ -1180,8 +1163,8 @@ void KinematicBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("_direct_state_changed"), &KinematicBody3D::_direct_state_changed); ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia", "exclude_raycast_shapes", "test_only"), &KinematicBody3D::_move, DEFVAL(true), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("move_and_slide_with_snap", "linear_velocity", "snap", "up_direction", "stop_on_slope", "max_slides", "floor_max_angle", "infinite_inertia"), &KinematicBody3D::move_and_slide_with_snap, DEFVAL(Vector3(0, 0, 0)), DEFVAL(false), DEFVAL(4), DEFVAL(Math::deg2rad((real_t)45.0)), DEFVAL(true)); ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody3D::test_move, DEFVAL(true)); @@ -1221,11 +1204,6 @@ void KinematicBody3D::_direct_state_changed(Object *p_state) { KinematicBody3D::KinematicBody3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_KINEMATIC) { - locked_axis = 0; - on_floor = false; - on_ceiling = false; - on_wall = false; - set_safe_margin(0.001); PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); } @@ -1716,6 +1694,10 @@ bool PhysicalBone3D::SixDOFJointData::_set(const StringName &p_name, const Varia String path = p_name; + if (!path.begins_with("joint_constraints/")) { + return false; + } + Vector3::Axis axis; { const String axis_s = path.get_slicec('/', 1); @@ -1872,6 +1854,10 @@ bool PhysicalBone3D::SixDOFJointData::_get(const StringName &p_name, Variant &r_ String path = p_name; + if (!path.begins_with("joint_constraints/")) { + return false; + } + int axis; { const String axis_s = path.get_slicec('/', 1); @@ -1971,7 +1957,7 @@ bool PhysicalBone3D::_set(const StringName &p_name, const Variant &p_value) { } if (joint_data) { - if (joint_data->_set(p_name, p_value)) { + if (joint_data->_set(p_name, p_value, joint)) { #ifdef TOOLS_ENABLED if (get_gizmo().is_valid()) { get_gizmo()->redraw(); @@ -2026,7 +2012,7 @@ void PhysicalBone3D::_notification(int p_what) { update_bone_id(); reset_to_rest_position(); reset_physics_simulation_state(); - if (!joint.is_valid() && joint_data) { + if (joint_data) { _reload_joint(); } break; @@ -2037,10 +2023,7 @@ void PhysicalBone3D::_notification(int p_what) { } } parent_skeleton = nullptr; - if (joint.is_valid()) { - PhysicsServer3D::get_singleton()->free(joint); - joint = RID(); - } + PhysicsServer3D::get_singleton()->joint_clear(joint); break; case NOTIFICATION_TRANSFORM_CHANGED: if (Engine::get_singleton()->is_editor_hint()) { @@ -2190,17 +2173,14 @@ void PhysicalBone3D::_fix_joint_offset() { } void PhysicalBone3D::_reload_joint() { - if (joint.is_valid()) { - PhysicsServer3D::get_singleton()->free(joint); - joint = RID(); - } - if (!parent_skeleton) { + PhysicsServer3D::get_singleton()->joint_clear(joint); return; } PhysicalBone3D *body_a = parent_skeleton->get_physical_bone_parent(bone_id); if (!body_a) { + PhysicsServer3D::get_singleton()->joint_clear(joint); return; } @@ -2210,7 +2190,7 @@ void PhysicalBone3D::_reload_joint() { switch (get_joint_type()) { case JOINT_TYPE_PIN: { - joint = PhysicsServer3D::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); + PhysicsServer3D::get_singleton()->joint_make_pin(joint, body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin); const PinJointData *pjd(static_cast<const PinJointData *>(joint_data)); PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_BIAS, pjd->bias); PhysicsServer3D::get_singleton()->pin_joint_set_param(joint, PhysicsServer3D::PIN_JOINT_DAMPING, pjd->damping); @@ -2218,7 +2198,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_CONE: { - joint = PhysicsServer3D::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_cone_twist(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data)); PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span); PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer3D::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span); @@ -2228,7 +2208,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_HINGE: { - joint = PhysicsServer3D::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_hinge(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data)); PhysicsServer3D::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled); PhysicsServer3D::get_singleton()->hinge_joint_set_param(joint, PhysicsServer3D::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper); @@ -2239,7 +2219,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_SLIDER: { - joint = PhysicsServer3D::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_slider(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data)); PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper); PhysicsServer3D::get_singleton()->slider_joint_set_param(joint, PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower); @@ -2254,7 +2234,7 @@ void PhysicalBone3D::_reload_joint() { } break; case JOINT_TYPE_6DOF: { - joint = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset); + PhysicsServer3D::get_singleton()->joint_make_generic_6dof(joint, body_a->get_rid(), local_a, get_rid(), joint_offset); const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data)); for (int axis = 0; axis < 3; ++axis) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled); @@ -2347,7 +2327,7 @@ void PhysicalBone3D::set_joint_type(JointType p_joint_type) { _reload_joint(); #ifdef TOOLS_ENABLED - _change_notify(); + notify_property_list_changed(); if (get_gizmo().is_valid()) { get_gizmo()->redraw(); } @@ -2362,7 +2342,6 @@ void PhysicalBone3D::set_joint_offset(const Transform &p_offset) { joint_offset = p_offset; _update_joint_offset(); - _change_notify("joint_rotation_degrees"); } const Transform &PhysicalBone3D::get_joint_offset() const { @@ -2373,7 +2352,6 @@ void PhysicalBone3D::set_joint_rotation(const Vector3 &p_euler_rad) { joint_offset.basis.set_euler_scale(p_euler_rad, joint_offset.basis.get_scale()); _update_joint_offset(); - _change_notify("joint_offset"); } Vector3 PhysicalBone3D::get_joint_rotation() const { @@ -2381,11 +2359,11 @@ Vector3 PhysicalBone3D::get_joint_rotation() const { } void PhysicalBone3D::set_joint_rotation_degrees(const Vector3 &p_euler_deg) { - set_joint_rotation(p_euler_deg * Math_PI / 180.0); + set_joint_rotation(p_euler_deg * (Math_PI / 180.0)); } Vector3 PhysicalBone3D::get_joint_rotation_degrees() const { - return get_joint_rotation() * 180.0 / Math_PI; + return get_joint_rotation() * (180.0 / Math_PI); } const Transform &PhysicalBone3D::get_body_offset() const { @@ -2508,6 +2486,7 @@ bool PhysicalBone3D::get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const { PhysicalBone3D::PhysicalBone3D() : PhysicsBody3D(PhysicsServer3D::BODY_MODE_STATIC) { + joint = PhysicsServer3D::get_singleton()->joint_create(); reset_physics_simulation_state(); } @@ -2515,6 +2494,7 @@ PhysicalBone3D::~PhysicalBone3D() { if (joint_data) { memdelete(joint_data); } + PhysicsServer3D::get_singleton()->free(joint); } void PhysicalBone3D::update_bone_id() { diff --git a/scene/3d/physics_body_3d.h b/scene/3d/physics_body_3d.h index 58eebc90ce..1450fce6a6 100644 --- a/scene/3d/physics_body_3d.h +++ b/scene/3d/physics_body_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,7 +50,7 @@ protected: public: virtual Vector3 get_linear_velocity() const; virtual Vector3 get_angular_velocity() const; - virtual float get_inverse_mass() const; + virtual real_t get_inverse_mass() const; void set_collision_layer(uint32_t p_layer); uint32_t get_collision_layer() const; @@ -111,31 +111,31 @@ public: }; protected: - bool can_sleep; - PhysicsDirectBodyState3D *state; - Mode mode; + bool can_sleep = true; + PhysicsDirectBodyState3D *state = nullptr; + Mode mode = MODE_RIGID; - real_t mass; + real_t mass = 1.0; Ref<PhysicsMaterial> physics_material_override; Vector3 linear_velocity; Vector3 angular_velocity; Basis inverse_inertia_tensor; - real_t gravity_scale; - real_t linear_damp; - real_t angular_damp; + real_t gravity_scale = 1.0; + real_t linear_damp = -1.0; + real_t angular_damp = -1.0; - bool sleeping; - bool ccd; + bool sleeping = false; + bool ccd = false; - int max_contacts_reported; + int max_contacts_reported = 0; - bool custom_integrator; + bool custom_integrator = false; struct ShapePair { - int body_shape; - int local_shape; - bool tagged; + int body_shape = 0; + int local_shape = 0; + bool tagged = false; bool operator<(const ShapePair &p_sp) const { if (body_shape == p_sp.body_shape) { return local_shape < p_sp.local_shape; @@ -157,16 +157,16 @@ protected: }; struct BodyState { //int rc; - bool in_tree; + bool in_tree = false; VSet<ShapePair> shapes; }; struct ContactMonitor { - bool locked; + bool locked = false; Map<ObjectID, BodyState> body_map; }; - ContactMonitor *contact_monitor; + ContactMonitor *contact_monitor = nullptr; void _body_enter_tree(ObjectID p_id); void _body_exit_tree(ObjectID p_id); @@ -183,7 +183,7 @@ public: void set_mass(real_t p_mass); real_t get_mass() const; - virtual float get_inverse_mass() const override { return 1.0 / mass; } + virtual real_t get_inverse_mass() const override { return 1.0 / mass; } void set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override); Ref<PhysicsMaterial> get_physics_material_override() const; @@ -261,27 +261,27 @@ public: Vector3 collider_vel; ObjectID collider; RID collider_rid; - int collider_shape; + int collider_shape = 0; Variant collider_metadata; Vector3 remainder; Vector3 travel; - int local_shape; + int local_shape = 0; }; private: Vector3 linear_velocity; Vector3 angular_velocity; - uint16_t locked_axis; + uint16_t locked_axis = 0; - float margin; + real_t margin; Vector3 floor_normal; Vector3 floor_velocity; RID on_floor_body; - bool on_floor; - bool on_ceiling; - bool on_wall; + bool on_floor = false; + bool on_ceiling = false; + bool on_wall = false; Vector<Collision> colliders; Vector<Ref<KinematicCollision3D>> slide_colliders; Ref<KinematicCollision3D> motion_cache; @@ -309,11 +309,11 @@ public: void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_lock); bool get_axis_lock(PhysicsServer3D::BodyAxis p_axis) const; - void set_safe_margin(float p_margin); - float get_safe_margin() const; + void set_safe_margin(real_t p_margin); + real_t get_safe_margin() const; - Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); - Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45), bool p_infinite_inertia = true); + Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); + Vector3 move_and_slide_with_snap(const Vector3 &p_linear_velocity, const Vector3 &p_snap, const Vector3 &p_up_direction = Vector3(0, 0, 0), bool p_stop_on_slope = false, int p_max_slides = 4, real_t p_floor_max_angle = Math::deg2rad((real_t)45.0), bool p_infinite_inertia = true); bool is_on_floor() const; bool is_on_wall() const; bool is_on_ceiling() const; @@ -370,7 +370,7 @@ public: virtual JointType get_joint_type() { return JOINT_TYPE_NONE; } /// "j" is used to set the parameter inside the PhysicsServer3D - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; @@ -380,105 +380,91 @@ public: struct PinJointData : public JointData { virtual JointType get_joint_type() { return JOINT_TYPE_PIN; } - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; real_t bias = 0.3; - real_t damping = 1.; - real_t impulse_clamp = 0; - - PinJointData() {} + real_t damping = 1.0; + real_t impulse_clamp = 0.0; }; struct ConeJointData : public JointData { virtual JointType get_joint_type() { return JOINT_TYPE_CONE; } - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; - real_t swing_span; + real_t swing_span = Math_PI * 0.25; real_t twist_span = Math_PI; real_t bias = 0.3; real_t softness = 0.8; real_t relaxation = 1.; - - ConeJointData() : - swing_span(Math_PI * 0.25) {} }; struct HingeJointData : public JointData { virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; } - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; bool angular_limit_enabled = false; - real_t angular_limit_upper; - real_t angular_limit_lower; + real_t angular_limit_upper = Math_PI * 0.5; + real_t angular_limit_lower = -Math_PI * 0.5; real_t angular_limit_bias = 0.3; real_t angular_limit_softness = 0.9; real_t angular_limit_relaxation = 1.; - - HingeJointData() : - - angular_limit_upper(Math_PI * 0.5), - angular_limit_lower(-Math_PI * 0.5) {} }; struct SliderJointData : public JointData { virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; } - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; - real_t linear_limit_upper = 1.; - real_t linear_limit_lower = -1.; - real_t linear_limit_softness = 1.; + real_t linear_limit_upper = 1.0; + real_t linear_limit_lower = -1.0; + real_t linear_limit_softness = 1.0; real_t linear_limit_restitution = 0.7; - real_t linear_limit_damping = 1.; - real_t angular_limit_upper = 0; - real_t angular_limit_lower = 0; - real_t angular_limit_softness = 1.; + real_t linear_limit_damping = 1.0; + real_t angular_limit_upper = 0.0; + real_t angular_limit_lower = 0.0; + real_t angular_limit_softness = 1.0; real_t angular_limit_restitution = 0.7; - real_t angular_limit_damping = 1.; - - SliderJointData() {} + real_t angular_limit_damping = 1.0; }; struct SixDOFJointData : public JointData { struct SixDOFAxisData { bool linear_limit_enabled = true; - real_t linear_limit_upper = 0; - real_t linear_limit_lower = 0; + real_t linear_limit_upper = 0.0; + real_t linear_limit_lower = 0.0; real_t linear_limit_softness = 0.7; real_t linear_restitution = 0.5; - real_t linear_damping = 1.; + real_t linear_damping = 1.0; bool linear_spring_enabled = false; - real_t linear_spring_stiffness = 0; - real_t linear_spring_damping = 0; - real_t linear_equilibrium_point = 0; + real_t linear_spring_stiffness = 0.0; + real_t linear_spring_damping = 0.0; + real_t linear_equilibrium_point = 0.0; bool angular_limit_enabled = true; - real_t angular_limit_upper = 0; - real_t angular_limit_lower = 0; + real_t angular_limit_upper = 0.0; + real_t angular_limit_lower = 0.0; real_t angular_limit_softness = 0.5; - real_t angular_restitution = 0; - real_t angular_damping = 1.; + real_t angular_restitution = 0.0; + real_t angular_damping = 1.0; real_t erp = 0.5; bool angular_spring_enabled = false; - real_t angular_spring_stiffness = 0; - real_t angular_spring_damping = 0.; - real_t angular_equilibrium_point = 0; - - SixDOFAxisData() {} + real_t angular_spring_stiffness = 0.0; + real_t angular_spring_damping = 0.0; + real_t angular_equilibrium_point = 0.0; }; virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; } - virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID()); + virtual bool _set(const StringName &p_name, const Variant &p_value, RID j); virtual bool _get(const StringName &p_name, Variant &r_ret) const; virtual void _get_property_list(List<PropertyInfo> *p_list) const; @@ -505,12 +491,12 @@ private: int bone_id = -1; String bone_name; - real_t bounce = 0; - real_t mass = 1; - real_t friction = 1; - real_t gravity_scale = 1; - real_t linear_damp = -1; - real_t angular_damp = -1; + real_t bounce = 0.0; + real_t mass = 1.0; + real_t friction = 1.0; + real_t gravity_scale = 1.0; + real_t linear_damp = -1.0; + real_t angular_damp = -1.0; bool can_sleep = true; protected: diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index 06de5ad0ae..de9c75621b 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -30,75 +30,106 @@ #include "physics_joint_3d.h" -void Joint3D::_update_joint(bool p_only_free) { - if (joint.is_valid()) { - if (ba.is_valid() && bb.is_valid()) { - PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb); - } +#include "scene/scene_string_names.h" - PhysicsServer3D::get_singleton()->free(joint); - joint = RID(); - ba = RID(); - bb = RID(); +void Joint3D::_disconnect_signals() { + Node *node_a = get_node_or_null(a); + PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); + if (body_a) { + body_a->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); } + Node *node_b = get_node_or_null(b); + PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); + if (body_b) { + body_b->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } +} + +void Joint3D::_body_exit_tree() { + _disconnect_signals(); + _update_joint(true); +} + +void Joint3D::_update_joint(bool p_only_free) { + if (ba.is_valid() && bb.is_valid()) { + PhysicsServer3D::get_singleton()->body_remove_collision_exception(ba, bb); + PhysicsServer3D::get_singleton()->body_remove_collision_exception(bb, ba); + } + + ba = RID(); + bb = RID(); + + configured = false; + if (p_only_free || !is_inside_tree()) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = String(); return; } - Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)nullptr; - Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)nullptr; + Node *node_a = get_node_or_null(a); + Node *node_b = get_node_or_null(b); PhysicsBody3D *body_a = Object::cast_to<PhysicsBody3D>(node_a); PhysicsBody3D *body_b = Object::cast_to<PhysicsBody3D>(node_b); if (node_a && !body_a && node_b && !body_b) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Node A and Node B must be PhysicsBody3Ds"); update_configuration_warning(); return; } if (node_a && !body_a) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Node A must be a PhysicsBody3D"); update_configuration_warning(); return; } if (node_b && !body_b) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Node B must be a PhysicsBody3D"); update_configuration_warning(); return; } if (!body_a && !body_b) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Joint is not connected to any PhysicsBody3Ds"); update_configuration_warning(); return; } if (body_a == body_b) { + PhysicsServer3D::get_singleton()->joint_clear(joint); warning = TTR("Node A and Node B must be different PhysicsBody3Ds"); update_configuration_warning(); return; } - if (!body_a) { - SWAP(body_a, body_b); - } - warning = String(); update_configuration_warning(); - joint = _configure_joint(body_a, body_b); + configured = true; - ERR_FAIL_COND_MSG(!joint.is_valid(), "Failed to configure the joint."); + if (body_a) { + _configure_joint(joint, body_a, body_b); + } else if (body_b) { + _configure_joint(joint, body_b, nullptr); + } PhysicsServer3D::get_singleton()->joint_set_solver_priority(joint, solver_priority); - ba = body_a->get_rid(); + if (body_a) { + ba = body_a->get_rid(); + body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); + } + if (body_b) { bb = body_b->get_rid(); + body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree)); } PhysicsServer3D::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); @@ -109,6 +140,10 @@ void Joint3D::set_node_a(const NodePath &p_node_a) { return; } + if (joint.is_valid()) { + _disconnect_signals(); + } + a = p_node_a; _update_joint(); } @@ -121,6 +156,11 @@ void Joint3D::set_node_b(const NodePath &p_node_b) { if (b == p_node_b) { return; } + + if (joint.is_valid()) { + _disconnect_signals(); + } + b = p_node_b; _update_joint(); } @@ -147,6 +187,7 @@ void Joint3D::_notification(int p_what) { } break; case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { + _disconnect_signals(); _update_joint(true); } } break; @@ -168,8 +209,8 @@ bool Joint3D::get_exclude_nodes_from_collision() const { String Joint3D::get_configuration_warning() const { String node_warning = Node3D::get_configuration_warning(); - if (!warning.empty()) { - if (!node_warning.empty()) { + if (!warning.is_empty()) { + if (!node_warning.is_empty()) { node_warning += "\n\n"; } node_warning += warning; @@ -199,9 +240,12 @@ void Joint3D::_bind_methods() { } Joint3D::Joint3D() { - exclude_from_collision = true; - solver_priority = 1; set_notify_transform(true); + joint = PhysicsServer3D::get_singleton()->joint_create(); +} + +Joint3D::~Joint3D() { + PhysicsServer3D::get_singleton()->free(joint); } /////////////////////////////////// @@ -219,20 +263,20 @@ void PinJoint3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_IMPULSE_CLAMP); } -void PinJoint3D::set_param(Param p_param, float p_value) { +void PinJoint3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, 3); params[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer3D::PinJointParam(p_param), p_value); } } -float PinJoint3D::get_param(Param p_param) const { +real_t PinJoint3D::get_param(Param p_param) const { ERR_FAIL_INDEX_V(p_param, 3, 0); return params[p_param]; } -RID PinJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { +void PinJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Vector3 pinpos = get_global_transform().origin; Vector3 local_a = body_a->get_global_transform().affine_inverse().xform(pinpos); Vector3 local_b; @@ -243,11 +287,10 @@ RID PinJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { local_b = pinpos; } - RID j = PhysicsServer3D::get_singleton()->joint_create_pin(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + PhysicsServer3D::get_singleton()->joint_make_pin(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); for (int i = 0; i < 3; i++) { - PhysicsServer3D::get_singleton()->pin_joint_set_param(j, PhysicsServer3D::PinJointParam(i), params[i]); + PhysicsServer3D::get_singleton()->pin_joint_set_param(p_joint, PhysicsServer3D::PinJointParam(i), params[i]); } - return j; } PinJoint3D::PinJoint3D() { @@ -260,19 +303,19 @@ PinJoint3D::PinJoint3D() { /////////////////////////////////// -void HingeJoint3D::_set_upper_limit(float p_limit) { +void HingeJoint3D::_set_upper_limit(real_t p_limit) { set_param(PARAM_LIMIT_UPPER, Math::deg2rad(p_limit)); } -float HingeJoint3D::_get_upper_limit() const { +real_t HingeJoint3D::_get_upper_limit() const { return Math::rad2deg(get_param(PARAM_LIMIT_UPPER)); } -void HingeJoint3D::_set_lower_limit(float p_limit) { +void HingeJoint3D::_set_lower_limit(real_t p_limit) { set_param(PARAM_LIMIT_LOWER, Math::deg2rad(p_limit)); } -float HingeJoint3D::_get_lower_limit() const { +real_t HingeJoint3D::_get_lower_limit() const { return Math::rad2deg(get_param(PARAM_LIMIT_LOWER)); } @@ -317,17 +360,17 @@ void HingeJoint3D::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_MAX); } -void HingeJoint3D::set_param(Param p_param, float p_value) { +void HingeJoint3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer3D::HingeJointParam(p_param), p_value); } update_gizmo(); } -float HingeJoint3D::get_param(Param p_param) const { +real_t HingeJoint3D::get_param(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params[p_param]; } @@ -335,7 +378,7 @@ float HingeJoint3D::get_param(Param p_param) const { void HingeJoint3D::set_flag(Flag p_flag, bool p_value) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags[p_flag] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer3D::HingeJointFlag(p_flag), p_value); } @@ -347,7 +390,7 @@ bool HingeJoint3D::get_flag(Flag p_flag) const { return flags[p_flag]; } -RID HingeJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { +void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Transform gt = get_global_transform(); Transform ainv = body_a->get_global_transform().affine_inverse(); @@ -362,15 +405,14 @@ RID HingeJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) local_b.orthonormalize(); - RID j = PhysicsServer3D::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + PhysicsServer3D::get_singleton()->joint_make_hinge(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->hinge_joint_set_param(j, PhysicsServer3D::HingeJointParam(i), params[i]); + PhysicsServer3D::get_singleton()->hinge_joint_set_param(p_joint, PhysicsServer3D::HingeJointParam(i), params[i]); } for (int i = 0; i < FLAG_MAX; i++) { set_flag(Flag(i), flags[i]); - PhysicsServer3D::get_singleton()->hinge_joint_set_flag(j, PhysicsServer3D::HingeJointFlag(i), flags[i]); + PhysicsServer3D::get_singleton()->hinge_joint_set_flag(p_joint, PhysicsServer3D::HingeJointFlag(i), flags[i]); } - return j; } HingeJoint3D::HingeJoint3D() { @@ -391,19 +433,19 @@ HingeJoint3D::HingeJoint3D() { ////////////////////////////////// -void SliderJoint3D::_set_upper_limit_angular(float p_limit_angular) { +void SliderJoint3D::_set_upper_limit_angular(real_t p_limit_angular) { set_param(PARAM_ANGULAR_LIMIT_UPPER, Math::deg2rad(p_limit_angular)); } -float SliderJoint3D::_get_upper_limit_angular() const { +real_t SliderJoint3D::_get_upper_limit_angular() const { return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_UPPER)); } -void SliderJoint3D::_set_lower_limit_angular(float p_limit_angular) { +void SliderJoint3D::_set_lower_limit_angular(real_t p_limit_angular) { set_param(PARAM_ANGULAR_LIMIT_LOWER, Math::deg2rad(p_limit_angular)); } -float SliderJoint3D::_get_lower_limit_angular() const { +real_t SliderJoint3D::_get_lower_limit_angular() const { return Math::rad2deg(get_param(PARAM_ANGULAR_LIMIT_LOWER)); } @@ -468,21 +510,21 @@ void SliderJoint3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_MAX); } -void SliderJoint3D::set_param(Param p_param, float p_value) { +void SliderJoint3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer3D::SliderJointParam(p_param), p_value); } update_gizmo(); } -float SliderJoint3D::get_param(Param p_param) const { +real_t SliderJoint3D::get_param(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params[p_param]; } -RID SliderJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { +void SliderJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Transform gt = get_global_transform(); Transform ainv = body_a->get_global_transform().affine_inverse(); @@ -497,12 +539,10 @@ RID SliderJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b local_b.orthonormalize(); - RID j = PhysicsServer3D::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + PhysicsServer3D::get_singleton()->joint_make_slider(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->slider_joint_set_param(j, PhysicsServer3D::SliderJointParam(i), params[i]); + PhysicsServer3D::get_singleton()->slider_joint_set_param(p_joint, PhysicsServer3D::SliderJointParam(i), params[i]); } - - return j; } SliderJoint3D::SliderJoint3D() { @@ -533,19 +573,19 @@ SliderJoint3D::SliderJoint3D() { ////////////////////////////////// -void ConeTwistJoint3D::_set_swing_span(float p_limit_angular) { +void ConeTwistJoint3D::_set_swing_span(real_t p_limit_angular) { set_param(PARAM_SWING_SPAN, Math::deg2rad(p_limit_angular)); } -float ConeTwistJoint3D::_get_swing_span() const { +real_t ConeTwistJoint3D::_get_swing_span() const { return Math::rad2deg(get_param(PARAM_SWING_SPAN)); } -void ConeTwistJoint3D::_set_twist_span(float p_limit_angular) { +void ConeTwistJoint3D::_set_twist_span(real_t p_limit_angular) { set_param(PARAM_TWIST_SPAN, Math::deg2rad(p_limit_angular)); } -float ConeTwistJoint3D::_get_twist_span() const { +real_t ConeTwistJoint3D::_get_twist_span() const { return Math::rad2deg(get_param(PARAM_TWIST_SPAN)); } @@ -574,22 +614,22 @@ void ConeTwistJoint3D::_bind_methods() { BIND_ENUM_CONSTANT(PARAM_MAX); } -void ConeTwistJoint3D::set_param(Param p_param, float p_value) { +void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value); } update_gizmo(); } -float ConeTwistJoint3D::get_param(Param p_param) const { +real_t ConeTwistJoint3D::get_param(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params[p_param]; } -RID ConeTwistJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { +void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Transform gt = get_global_transform(); //Vector3 cone_twistpos = gt.origin; //Vector3 cone_twistdir = gt.basis.get_axis(2); @@ -607,12 +647,10 @@ RID ConeTwistJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *bod local_b.orthonormalize(); - RID j = PhysicsServer3D::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + PhysicsServer3D::get_singleton()->joint_make_cone_twist(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer3D::ConeTwistJointParam(i), params[i]); + PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(p_joint, PhysicsServer3D::ConeTwistJointParam(i), params[i]); } - - return j; } ConeTwistJoint3D::ConeTwistJoint3D() { @@ -625,51 +663,51 @@ ConeTwistJoint3D::ConeTwistJoint3D() { ///////////////////////////////////////////////////////////////////// -void Generic6DOFJoint3D::_set_angular_hi_limit_x(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_hi_limit_x(real_t p_limit_angular) { set_param_x(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_hi_limit_x() const { +real_t Generic6DOFJoint3D::_get_angular_hi_limit_x() const { return Math::rad2deg(get_param_x(PARAM_ANGULAR_UPPER_LIMIT)); } -void Generic6DOFJoint3D::_set_angular_lo_limit_x(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_lo_limit_x(real_t p_limit_angular) { set_param_x(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_lo_limit_x() const { +real_t Generic6DOFJoint3D::_get_angular_lo_limit_x() const { return Math::rad2deg(get_param_x(PARAM_ANGULAR_LOWER_LIMIT)); } -void Generic6DOFJoint3D::_set_angular_hi_limit_y(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_hi_limit_y(real_t p_limit_angular) { set_param_y(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_hi_limit_y() const { +real_t Generic6DOFJoint3D::_get_angular_hi_limit_y() const { return Math::rad2deg(get_param_y(PARAM_ANGULAR_UPPER_LIMIT)); } -void Generic6DOFJoint3D::_set_angular_lo_limit_y(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_lo_limit_y(real_t p_limit_angular) { set_param_y(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_lo_limit_y() const { +real_t Generic6DOFJoint3D::_get_angular_lo_limit_y() const { return Math::rad2deg(get_param_y(PARAM_ANGULAR_LOWER_LIMIT)); } -void Generic6DOFJoint3D::_set_angular_hi_limit_z(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_hi_limit_z(real_t p_limit_angular) { set_param_z(PARAM_ANGULAR_UPPER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_hi_limit_z() const { +real_t Generic6DOFJoint3D::_get_angular_hi_limit_z() const { return Math::rad2deg(get_param_z(PARAM_ANGULAR_UPPER_LIMIT)); } -void Generic6DOFJoint3D::_set_angular_lo_limit_z(float p_limit_angular) { +void Generic6DOFJoint3D::_set_angular_lo_limit_z(real_t p_limit_angular) { set_param_z(PARAM_ANGULAR_LOWER_LIMIT, Math::deg2rad(p_limit_angular)); } -float Generic6DOFJoint3D::_get_angular_lo_limit_z() const { +real_t Generic6DOFJoint3D::_get_angular_lo_limit_z() const { return Math::rad2deg(get_param_z(PARAM_ANGULAR_LOWER_LIMIT)); } @@ -831,45 +869,45 @@ void Generic6DOFJoint3D::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_MAX); } -void Generic6DOFJoint3D::set_param_x(Param p_param, float p_value) { +void Generic6DOFJoint3D::set_param_x(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params_x[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value); } update_gizmo(); } -float Generic6DOFJoint3D::get_param_x(Param p_param) const { +real_t Generic6DOFJoint3D::get_param_x(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params_x[p_param]; } -void Generic6DOFJoint3D::set_param_y(Param p_param, float p_value) { +void Generic6DOFJoint3D::set_param_y(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params_y[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value); } update_gizmo(); } -float Generic6DOFJoint3D::get_param_y(Param p_param) const { +real_t Generic6DOFJoint3D::get_param_y(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params_y[p_param]; } -void Generic6DOFJoint3D::set_param_z(Param p_param, float p_value) { +void Generic6DOFJoint3D::set_param_z(Param p_param, real_t p_value) { ERR_FAIL_INDEX(p_param, PARAM_MAX); params_z[p_param] = p_value; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value); } update_gizmo(); } -float Generic6DOFJoint3D::get_param_z(Param p_param) const { +real_t Generic6DOFJoint3D::get_param_z(Param p_param) const { ERR_FAIL_INDEX_V(p_param, PARAM_MAX, 0); return params_z[p_param]; } @@ -877,7 +915,7 @@ float Generic6DOFJoint3D::get_param_z(Param p_param) const { void Generic6DOFJoint3D::set_flag_x(Flag p_flag, bool p_enabled) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags_x[p_flag] = p_enabled; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled); } update_gizmo(); @@ -891,7 +929,7 @@ bool Generic6DOFJoint3D::get_flag_x(Flag p_flag) const { void Generic6DOFJoint3D::set_flag_y(Flag p_flag, bool p_enabled) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags_y[p_flag] = p_enabled; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled); } update_gizmo(); @@ -905,7 +943,7 @@ bool Generic6DOFJoint3D::get_flag_y(Flag p_flag) const { void Generic6DOFJoint3D::set_flag_z(Flag p_flag, bool p_enabled) { ERR_FAIL_INDEX(p_flag, FLAG_MAX); flags_z[p_flag] = p_enabled; - if (get_joint().is_valid()) { + if (is_configured()) { PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled); } update_gizmo(); @@ -916,7 +954,7 @@ bool Generic6DOFJoint3D::get_flag_z(Flag p_flag) const { return flags_z[p_flag]; } -RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) { +void Generic6DOFJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) { Transform gt = get_global_transform(); //Vector3 cone_twistpos = gt.origin; //Vector3 cone_twistdir = gt.basis.get_axis(2); @@ -934,19 +972,17 @@ RID Generic6DOFJoint3D::_configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *b local_b.orthonormalize(); - RID j = PhysicsServer3D::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); + PhysicsServer3D::get_singleton()->joint_make_generic_6dof(p_joint, body_a->get_rid(), local_a, body_b ? body_b->get_rid() : RID(), local_b); for (int i = 0; i < PARAM_MAX; i++) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(i), params_x[i]); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(i), params_y[i]); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(j, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(i), params_z[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(i), params_x[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(i), params_y[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(p_joint, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(i), params_z[i]); } for (int i = 0; i < FLAG_MAX; i++) { - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_x[i]); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_y[i]); - PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(j, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_z[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_x[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_y[i]); + PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(p_joint, Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(i), flags_z[i]); } - - return j; } Generic6DOFJoint3D::Generic6DOFJoint3D() { diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h index 250ae8bf52..f624ba602b 100644 --- a/scene/3d/physics_joint_3d.h +++ b/scene/3d/physics_joint_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,19 +44,24 @@ class Joint3D : public Node3D { NodePath a; NodePath b; - int solver_priority; - bool exclude_from_collision; + int solver_priority = 1; + bool exclude_from_collision = true; String warning; + bool configured = false; protected: + void _disconnect_signals(); + void _body_exit_tree(); void _update_joint(bool p_only_free = false); void _notification(int p_what); - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) = 0; static void _bind_methods(); + _FORCE_INLINE_ bool is_configured() const { return configured; } + public: virtual String get_configuration_warning() const override; @@ -74,6 +79,7 @@ public: RID get_joint() const { return joint; } Joint3D(); + ~Joint3D(); }; /////////////////////////////////////////// @@ -89,13 +95,13 @@ public: }; protected: - float params[3]; - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + real_t params[3]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); public: - void set_param(Param p_param, float p_value); - float get_param(Param p_param) const; + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; PinJoint3D(); }; @@ -125,20 +131,20 @@ public: }; protected: - float params[PARAM_MAX]; + real_t params[PARAM_MAX]; bool flags[FLAG_MAX]; - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); - void _set_upper_limit(float p_limit); - float _get_upper_limit() const; + void _set_upper_limit(real_t p_limit); + real_t _get_upper_limit() const; - void _set_lower_limit(float p_limit); - float _get_lower_limit() const; + void _set_lower_limit(real_t p_limit); + real_t _get_lower_limit() const; public: - void set_param(Param p_param, float p_value); - float get_param(Param p_param) const; + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; void set_flag(Flag p_flag, bool p_value); bool get_flag(Flag p_flag) const; @@ -182,19 +188,19 @@ public: }; protected: - void _set_upper_limit_angular(float p_limit_angular); - float _get_upper_limit_angular() const; + void _set_upper_limit_angular(real_t p_limit_angular); + real_t _get_upper_limit_angular() const; - void _set_lower_limit_angular(float p_limit_angular); - float _get_lower_limit_angular() const; + void _set_lower_limit_angular(real_t p_limit_angular); + real_t _get_lower_limit_angular() const; - float params[PARAM_MAX]; - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + real_t params[PARAM_MAX]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); public: - void set_param(Param p_param, float p_value); - float get_param(Param p_param) const; + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; SliderJoint3D(); }; @@ -215,19 +221,19 @@ public: }; protected: - void _set_swing_span(float p_limit_angular); - float _get_swing_span() const; + void _set_swing_span(real_t p_limit_angular); + real_t _get_swing_span() const; - void _set_twist_span(float p_limit_angular); - float _get_twist_span() const; + void _set_twist_span(real_t p_limit_angular); + real_t _get_twist_span() const; - float params[PARAM_MAX]; - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + real_t params[PARAM_MAX]; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); public: - void set_param(Param p_param, float p_value); - float get_param(Param p_param) const; + void set_param(Param p_param, real_t p_value); + real_t get_param(Param p_param) const; ConeTwistJoint3D(); }; @@ -275,43 +281,43 @@ public: }; protected: - void _set_angular_hi_limit_x(float p_limit_angular); - float _get_angular_hi_limit_x() const; + void _set_angular_hi_limit_x(real_t p_limit_angular); + real_t _get_angular_hi_limit_x() const; - void _set_angular_hi_limit_y(float p_limit_angular); - float _get_angular_hi_limit_y() const; + void _set_angular_hi_limit_y(real_t p_limit_angular); + real_t _get_angular_hi_limit_y() const; - void _set_angular_hi_limit_z(float p_limit_angular); - float _get_angular_hi_limit_z() const; + void _set_angular_hi_limit_z(real_t p_limit_angular); + real_t _get_angular_hi_limit_z() const; - void _set_angular_lo_limit_x(float p_limit_angular); - float _get_angular_lo_limit_x() const; + void _set_angular_lo_limit_x(real_t p_limit_angular); + real_t _get_angular_lo_limit_x() const; - void _set_angular_lo_limit_y(float p_limit_angular); - float _get_angular_lo_limit_y() const; + void _set_angular_lo_limit_y(real_t p_limit_angular); + real_t _get_angular_lo_limit_y() const; - void _set_angular_lo_limit_z(float p_limit_angular); - float _get_angular_lo_limit_z() const; + void _set_angular_lo_limit_z(real_t p_limit_angular); + real_t _get_angular_lo_limit_z() const; - float params_x[PARAM_MAX]; + real_t params_x[PARAM_MAX]; bool flags_x[FLAG_MAX]; - float params_y[PARAM_MAX]; + real_t params_y[PARAM_MAX]; bool flags_y[FLAG_MAX]; - float params_z[PARAM_MAX]; + real_t params_z[PARAM_MAX]; bool flags_z[FLAG_MAX]; - virtual RID _configure_joint(PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; + virtual void _configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsBody3D *body_b) override; static void _bind_methods(); public: - void set_param_x(Param p_param, float p_value); - float get_param_x(Param p_param) const; + void set_param_x(Param p_param, real_t p_value); + real_t get_param_x(Param p_param) const; - void set_param_y(Param p_param, float p_value); - float get_param_y(Param p_param) const; + void set_param_y(Param p_param, real_t p_value); + real_t get_param_y(Param p_param) const; - void set_param_z(Param p_param, float p_value); - float get_param_z(Param p_param) const; + void set_param_z(Param p_param, real_t p_value); + real_t get_param_z(Param p_param) const; void set_flag_x(Flag p_flag, bool p_enabled); bool get_flag_x(Flag p_flag) const; diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp index e63c588e28..b231ba0df7 100644 --- a/scene/3d/position_3d.cpp +++ b/scene/3d/position_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h index 1c5f05ef95..065b14c3bd 100644 --- a/scene/3d/position_3d.h +++ b/scene/3d/position_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/proximity_group_3d.cpp b/scene/3d/proximity_group_3d.cpp index 7e25255885..9d9fea68b0 100644 --- a/scene/3d/proximity_group_3d.cpp +++ b/scene/3d/proximity_group_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/proximity_group_3d.h b/scene/3d/proximity_group_3d.h index d52843e9a2..05aa00b228 100644 --- a/scene/3d/proximity_group_3d.h +++ b/scene/3d/proximity_group_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index 811e8a331b..66f3e539a2 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,10 +37,13 @@ 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(); - } - if (is_inside_tree() && get_tree()->is_debugging_collisions_hint()) { + update_gizmo(); + + if (Engine::get_singleton()->is_editor_hint()) { + if (is_inside_tree()) { + _update_debug_shape_vertices(); + } + } else if (debug_shape) { _update_debug_shape(); } } @@ -146,16 +149,19 @@ bool RayCast3D::get_exclude_parent_body() const { void RayCast3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { + if (Engine::get_singleton()->is_editor_hint()) { + _update_debug_shape_vertices(); + } if (enabled && !Engine::get_singleton()->is_editor_hint()) { set_physics_process_internal(true); - - if (get_tree()->is_debugging_collisions_hint()) { - _update_debug_shape(); - } } else { set_physics_process_internal(false); } + if (get_tree()->is_debugging_collisions_hint()) { + _update_debug_shape(); + } + if (Object::cast_to<CollisionObject3D>(get_parent())) { if (exclude_parent_body) { exclude.insert(Object::cast_to<CollisionObject3D>(get_parent())->get_rid()); @@ -183,10 +189,7 @@ void RayCast3D::_notification(int p_what) { bool prev_collision_state = collided; _update_raycast_state(); if (prev_collision_state != collided && get_tree()->is_debugging_collisions_hint()) { - if (debug_material.is_valid()) { - Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D>>(debug_material); - line_material->set_albedo(collided ? Color(1.0, 0, 0) : Color(1.0, 0.8, 0.6)); - } + _update_debug_shape_material(true); } } break; @@ -310,6 +313,12 @@ void RayCast3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &RayCast3D::set_collide_with_bodies); ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &RayCast3D::is_collide_with_bodies_enabled); + ClassDB::bind_method(D_METHOD("set_debug_shape_custom_color", "debug_shape_custom_color"), &RayCast3D::set_debug_shape_custom_color); + ClassDB::bind_method(D_METHOD("get_debug_shape_custom_color"), &RayCast3D::get_debug_shape_custom_color); + + ClassDB::bind_method(D_METHOD("set_debug_shape_thickness", "debug_shape_thickness"), &RayCast3D::set_debug_shape_thickness); + ClassDB::bind_method(D_METHOD("get_debug_shape_thickness"), &RayCast3D::get_debug_shape_thickness); + 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, "target_position"), "set_target_position", "get_target_position"); @@ -318,16 +327,80 @@ void RayCast3D::_bind_methods() { ADD_GROUP("Collide With", "collide_with"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_areas", "is_collide_with_areas_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); + + ADD_GROUP("Debug Shape", "debug_shape"); + ADD_PROPERTY(PropertyInfo(Variant::COLOR, "debug_shape_custom_color"), "set_debug_shape_custom_color", "get_debug_shape_custom_color"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_shape_thickness", PROPERTY_HINT_RANGE, "1,5"), "set_debug_shape_thickness", "get_debug_shape_thickness"); } -void RayCast3D::_create_debug_shape() { - if (!debug_material.is_valid()) { - debug_material = Ref<StandardMaterial3D>(memnew(StandardMaterial3D)); +float RayCast3D::get_debug_shape_thickness() const { + return debug_shape_thickness; +} + +void RayCast3D::_update_debug_shape_vertices() { + debug_shape_vertices.clear(); + debug_line_vertices.clear(); + + if (target_position == Vector3()) { + return; + } + + debug_line_vertices.push_back(Vector3()); + debug_line_vertices.push_back(target_position); + + if (debug_shape_thickness > 1) { + float scale_factor = 100.0; + Vector3 dir = Vector3(target_position).normalized(); + // Draw truncated pyramid + Vector3 normal = (fabs(dir.x) + fabs(dir.y) > CMP_EPSILON) ? Vector3(-dir.y, dir.x, 0).normalized() : Vector3(0, -dir.z, dir.y).normalized(); + normal *= debug_shape_thickness / scale_factor; + int vertices_strip_order[14] = { 4, 5, 0, 1, 2, 5, 6, 4, 7, 0, 3, 2, 7, 6 }; + for (int v = 0; v < 14; v++) { + Vector3 vertex = vertices_strip_order[v] < 4 ? normal : normal / 3.0 + target_position; + debug_shape_vertices.push_back(vertex.rotated(dir, Math_PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25))); + } + } +} + +void RayCast3D::set_debug_shape_thickness(const float p_debug_shape_thickness) { + debug_shape_thickness = p_debug_shape_thickness; + update_gizmo(); + + if (Engine::get_singleton()->is_editor_hint()) { + if (is_inside_tree()) { + _update_debug_shape_vertices(); + } + } else if (debug_shape) { + _update_debug_shape(); + } +} + +const Vector<Vector3> &RayCast3D::get_debug_shape_vertices() const { + return debug_shape_vertices; +} + +const Vector<Vector3> &RayCast3D::get_debug_line_vertices() const { + return debug_line_vertices; +} - Ref<StandardMaterial3D> line_material = static_cast<Ref<StandardMaterial3D>>(debug_material); - line_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); - line_material->set_albedo(Color(1.0, 0.8, 0.6)); +void RayCast3D::set_debug_shape_custom_color(const Color &p_color) { + debug_shape_custom_color = p_color; + if (debug_material.is_valid()) { + _update_debug_shape_material(); } +} + +Ref<StandardMaterial3D> RayCast3D::get_debug_material() { + _update_debug_shape_material(); + return debug_material; +} + +const Color &RayCast3D::get_debug_shape_custom_color() const { + return debug_shape_custom_color; +} + +void RayCast3D::_create_debug_shape() { + _update_debug_shape_material(); Ref<ArrayMesh> mesh = memnew(ArrayMesh); @@ -338,6 +411,35 @@ void RayCast3D::_create_debug_shape() { debug_shape = mi; } +void RayCast3D::_update_debug_shape_material(bool p_check_collision) { + if (!debug_material.is_valid()) { + Ref<StandardMaterial3D> material = memnew(StandardMaterial3D); + debug_material = material; + + material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED); + material->set_transparency(BaseMaterial3D::TRANSPARENCY_ALPHA); + } + + Color color = debug_shape_custom_color; + if (color == Color(0.0, 0.0, 0.0)) { + // Use the default debug shape color defined in the Project Settings. + color = get_tree()->get_debug_collisions_color(); + } + + if (p_check_collision) { + if ((color.get_h() < 0.055 || color.get_h() > 0.945) && color.get_s() > 0.5 && color.get_v() > 0.5) { + // If base color is already quite reddish, highlight collision with green color + color = Color(0.0, 1.0, 0.0, color.a); + } else { + // Else, highlight collision with red color + color = Color(1.0, 0, 0, color.a); + } + } + + Ref<StandardMaterial3D> material = static_cast<Ref<StandardMaterial3D>>(debug_material); + material->set_albedo(color); +} + void RayCast3D::_update_debug_shape() { if (!enabled) { return; @@ -348,23 +450,34 @@ void RayCast3D::_update_debug_shape() { } MeshInstance3D *mi = static_cast<MeshInstance3D *>(debug_shape); - if (!mi->get_mesh().is_valid()) { + Ref<ArrayMesh> mesh = mi->get_mesh(); + if (!mesh.is_valid()) { return; } - Ref<ArrayMesh> mesh = mi->get_mesh(); + _update_debug_shape_vertices(); + mesh->clear_surfaces(); Array a; a.resize(Mesh::ARRAY_MAX); - Vector<Vector3> verts; - verts.push_back(Vector3()); - verts.push_back(target_position); - a[Mesh::ARRAY_VERTEX] = verts; + uint32_t flags = 0; + int surface_count = 0; - mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a); - mesh->surface_set_material(0, debug_material); + if (!debug_line_vertices.is_empty()) { + a[Mesh::ARRAY_VERTEX] = debug_line_vertices; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, a, Array(), Dictionary(), flags); + mesh->surface_set_material(surface_count, debug_material); + ++surface_count; + } + + if (!debug_shape_vertices.is_empty()) { + a[Mesh::ARRAY_VERTEX] = debug_shape_vertices; + mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLE_STRIP, a, Array(), Dictionary(), flags); + mesh->surface_set_material(surface_count, debug_material); + ++surface_count; + } } void RayCast3D::_clear_debug_shape() { @@ -383,13 +496,4 @@ void RayCast3D::_clear_debug_shape() { } RayCast3D::RayCast3D() { - enabled = true; - collided = false; - against_shape = 0; - collision_mask = 1; - target_position = Vector3(0, -1, 0); - debug_shape = nullptr; - exclude_parent_body = true; - collide_with_areas = false; - collide_with_bodies = true; } diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h index f4fe7ba621..968cede9f2 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/ray_cast_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,28 +36,34 @@ class RayCast3D : public Node3D { GDCLASS(RayCast3D, Node3D); - bool enabled; - bool collided; + bool enabled = true; + bool collided = false; ObjectID against; - int against_shape; + int against_shape = 0; Vector3 collision_point; Vector3 collision_normal; - Vector3 target_position; + Vector3 target_position = Vector3(0, -1, 0); Set<RID> exclude; - uint32_t collision_mask; - bool exclude_parent_body; + uint32_t collision_mask = 1; + bool exclude_parent_body = true; - Node *debug_shape; + Node *debug_shape = nullptr; Ref<Material> debug_material; + Color debug_shape_custom_color = Color(0.0, 0.0, 0.0); + int debug_shape_thickness = 2; + Vector<Vector3> debug_shape_vertices; + Vector<Vector3> debug_line_vertices; void _create_debug_shape(); void _update_debug_shape(); + void _update_debug_shape_material(bool p_check_collision = false); + void _update_debug_shape_vertices(); void _clear_debug_shape(); - bool collide_with_areas; - bool collide_with_bodies; + bool collide_with_areas = false; + bool collide_with_bodies = true; protected: void _notification(int p_what); @@ -86,6 +92,17 @@ public: void set_exclude_parent_body(bool p_exclude_parent_body); bool get_exclude_parent_body() const; + const Color &get_debug_shape_custom_color() const; + void set_debug_shape_custom_color(const Color &p_color); + + const Vector<Vector3> &get_debug_shape_vertices() const; + const Vector<Vector3> &get_debug_line_vertices() const; + + Ref<StandardMaterial3D> get_debug_material(); + + float get_debug_shape_thickness() const; + void set_debug_shape_thickness(const float p_debug_thickness); + void force_raycast_update(); bool is_colliding() const; Object *get_collider() const; diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp index c82ed423a7..ad24f39bce 100644 --- a/scene/3d/reflection_probe.cpp +++ b/scene/3d/reflection_probe.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,7 +42,7 @@ float ReflectionProbe::get_intensity() const { void ReflectionProbe::set_ambient_mode(AmbientMode p_mode) { ambient_mode = p_mode; RS::get_singleton()->reflection_probe_set_ambient_mode(probe, RS::ReflectionProbeAmbientMode(p_mode)); - _change_notify(); + notify_property_list_changed(); } ReflectionProbe::AmbientMode ReflectionProbe::get_ambient_mode() const { @@ -95,13 +95,12 @@ void ReflectionProbe::set_extents(const Vector3 &p_extents) { if (extents[i] - 0.01 < ABS(origin_offset[i])) { origin_offset[i] = SGN(origin_offset[i]) * (extents[i] - 0.01); - _change_notify("origin_offset"); } } RS::get_singleton()->reflection_probe_set_extents(probe, extents); RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset); - _change_notify("extents"); + update_gizmo(); } @@ -120,7 +119,6 @@ void ReflectionProbe::set_origin_offset(const Vector3 &p_extents) { RS::get_singleton()->reflection_probe_set_extents(probe, extents); RS::get_singleton()->reflection_probe_set_origin_offset(probe, origin_offset); - _change_notify("origin_offset"); update_gizmo(); } @@ -257,20 +255,6 @@ void ReflectionProbe::_bind_methods() { } ReflectionProbe::ReflectionProbe() { - intensity = 1.0; - ambient_mode = AMBIENT_ENVIRONMENT; - ambient_color = Color(0, 0, 0); - ambient_color_energy = 1.0; - max_distance = 0; - extents = Vector3(1, 1, 1); - origin_offset = Vector3(0, 0, 0); - box_projection = false; - interior = false; - enable_shadows = false; - cull_mask = (1 << 20) - 1; - update_mode = UPDATE_ONCE; - lod_threshold = 1.0; - probe = RenderingServer::get_singleton()->reflection_probe_create(); RS::get_singleton()->instance_set_base(get_instance(), probe); set_disable_scale(true); diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h index 4bff2f8bf9..15c2da3ae0 100644 --- a/scene/3d/reflection_probe.h +++ b/scene/3d/reflection_probe.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -53,20 +53,20 @@ public: private: RID probe; - float intensity; - float max_distance; - Vector3 extents; - Vector3 origin_offset; - bool box_projection; - bool enable_shadows; - bool interior; - AmbientMode ambient_mode; - Color ambient_color; - float ambient_color_energy; - float lod_threshold; - - uint32_t cull_mask; - UpdateMode update_mode; + float intensity = 1.0; + float max_distance = 0.0; + Vector3 extents = Vector3(1, 1, 1); + Vector3 origin_offset = Vector3(0, 0, 0); + bool box_projection = false; + bool enable_shadows = false; + bool interior = false; + AmbientMode ambient_mode = AMBIENT_ENVIRONMENT; + Color ambient_color = Color(0, 0, 0); + float ambient_color_energy = 1.0; + float lod_threshold = 1.0; + + uint32_t cull_mask = (1 << 20) - 1; + UpdateMode update_mode = UPDATE_ONCE; protected: static void _bind_methods(); diff --git a/scene/3d/remote_transform_3d.cpp b/scene/3d/remote_transform_3d.cpp index 358f9346f8..83ac813c53 100644 --- a/scene/3d/remote_transform_3d.cpp +++ b/scene/3d/remote_transform_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -183,7 +183,7 @@ 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))) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The \"Remote Path\" property must point to a valid Node3D or Node3D-derived node to work."); @@ -217,10 +217,5 @@ void RemoteTransform3D::_bind_methods() { } RemoteTransform3D::RemoteTransform3D() { - use_global_coordinates = true; - update_remote_position = true; - update_remote_rotation = true; - update_remote_scale = true; - set_notify_transform(true); } diff --git a/scene/3d/remote_transform_3d.h b/scene/3d/remote_transform_3d.h index 0ce30f7fce..21005d92d1 100644 --- a/scene/3d/remote_transform_3d.h +++ b/scene/3d/remote_transform_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,10 +40,10 @@ class RemoteTransform3D : public Node3D { ObjectID cache; - bool use_global_coordinates; - bool update_remote_position; - bool update_remote_rotation; - bool update_remote_scale; + bool use_global_coordinates = true; + bool update_remote_position = true; + bool update_remote_rotation = true; + bool update_remote_scale = true; void _update_remote(); void _update_cache(); diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index 4425af26f9..be62fe801f 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -304,7 +304,7 @@ void Skeleton3D::_notification(int p_what) { uint32_t bind_count = skin->get_bind_count(); if (E->get()->bind_count != bind_count) { - RS::get_singleton()->skeleton_allocate(skeleton, bind_count); + RS::get_singleton()->skeleton_allocate_data(skeleton, bind_count); E->get()->bind_count = bind_count; E->get()->skin_bone_indices.resize(bind_count); E->get()->skin_bone_indices_ptrs = E->get()->skin_bone_indices.ptrw(); @@ -927,10 +927,6 @@ void Skeleton3D::_bind_methods() { } Skeleton3D::Skeleton3D() { - animate_physical_bones = true; - dirty = false; - version = 1; - process_order_dirty = true; } Skeleton3D::~Skeleton3D() { diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h index c54f89d3ce..9772bfcc95 100644 --- a/scene/3d/skeleton_3d.h +++ b/scene/3d/skeleton_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -74,57 +74,44 @@ private: struct Bone { String name; - bool enabled; - int parent; - int sort_index; //used for re-sorting process order + bool enabled = true; + int parent = -1; + int sort_index = 0; //used for re-sorting process order - bool disable_rest; + bool disable_rest = false; Transform rest; Transform pose; Transform pose_global; - bool custom_pose_enable; + bool custom_pose_enable = false; Transform custom_pose; - float global_pose_override_amount; - bool global_pose_override_reset; + float global_pose_override_amount = 0.0; + bool global_pose_override_reset = false; Transform global_pose_override; #ifndef _3D_DISABLED - PhysicalBone3D *physical_bone; - PhysicalBone3D *cache_parent_physical_bone; + PhysicalBone3D *physical_bone = nullptr; + PhysicalBone3D *cache_parent_physical_bone = nullptr; #endif // _3D_DISABLED List<ObjectID> nodes_bound; - - Bone() { - parent = -1; - enabled = true; - disable_rest = false; - custom_pose_enable = false; - global_pose_override_amount = 0; - global_pose_override_reset = false; -#ifndef _3D_DISABLED - physical_bone = nullptr; - cache_parent_physical_bone = nullptr; -#endif // _3D_DISABLED - } }; Set<SkinReference *> skin_bindings; void _skin_changed(); - bool animate_physical_bones; + bool animate_physical_bones = true; Vector<Bone> bones; Vector<int> process_order; - bool process_order_dirty; + bool process_order_dirty = true; void _make_dirty(); - bool dirty; + bool dirty = false; - uint64_t version; + uint64_t version = 1; // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp index 32d7afd5df..85da546430 100644 --- a/scene/3d/skeleton_ik_3d.cpp +++ b/scene/3d/skeleton_ik_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -63,7 +63,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain chain.chain_root.bone = p_task->root_bone; chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(chain.chain_root.bone); chain.chain_root.current_pos = chain.chain_root.initial_transform.origin; - chain.chain_root.pb = p_task->skeleton->get_physical_bone(chain.chain_root.bone); chain.middle_chain_item = nullptr; // Holds all IDs that are composing a single chain in reverse order @@ -96,8 +95,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain if (!child_ci) { child_ci = sub_chain->add_child(chain_ids[i]); - child_ci->pb = p_task->skeleton->get_physical_bone(child_ci->bone); - child_ci->initial_transform = p_task->skeleton->get_bone_global_pose(child_ci->bone); child_ci->current_pos = child_ci->initial_transform.origin; @@ -123,7 +120,7 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain if (p_force_simple_chain) { // NOTE: - // This is an "hack" that force to create only one tip per chain since the solver of multi tip (end effector) + // This is a "hack" that force to create only one tip per chain since the solver of multi tip (end effector) // is not yet created. // Remove this code when this is done break; @@ -132,20 +129,6 @@ bool FabrikInverseKinematic::build_chain(Task *p_task, bool p_force_simple_chain return true; } -void FabrikInverseKinematic::update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item) { - if (!p_chain_item) { - return; - } - - p_chain_item->initial_transform = p_sk->get_bone_global_pose(p_chain_item->bone); - p_chain_item->current_pos = p_chain_item->initial_transform.origin; - - ChainItem *items = p_chain_item->children.ptrw(); - for (int i = 0; i < p_chain_item->children.size(); i += 1) { - update_chain(p_sk, items + i); - } -} - void FabrikInverseKinematic::solve_simple(Task *p_task, bool p_solve_magnet) { real_t distance_to_goal(1e4); real_t previous_distance_to_goal(0); @@ -204,7 +187,7 @@ void FabrikInverseKinematic::solve_simple_forwards(Chain &r_chain, bool p_solve_ while (sub_chain_root) { // Reach the tip sub_chain_root->current_pos = origin; - if (!sub_chain_root->children.empty()) { + if (!sub_chain_root->children.is_empty()) { ChainItem &child(sub_chain_root->children.write[0]); // Is not tip @@ -263,7 +246,7 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform &p_inverse_ p_task->end_effectors.write[0].goal_transform = p_inverse_transf * p_task->goal_global_transform; } else { // End effector in local transform - const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors.write[0].tip_bone)); + const Transform end_effector_pose(p_task->skeleton->get_bone_global_pose(p_task->end_effectors[0].tip_bone)); // Update the end_effector (local transform) by blending with current pose p_task->end_effectors.write[0].goal_transform = end_effector_pose.interpolate_with(p_inverse_transf * p_task->goal_global_transform, blending_delta); @@ -285,9 +268,11 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove p_task->skeleton->set_bone_global_pose_override(p_task->chain.tips[i].chain_item->bone, Transform(), 0.0, true); } - make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse().scaled(p_task->skeleton->get_global_transform().get_basis().get_scale()), blending_delta); + // Update the initial root transform + p_task->chain.chain_root.initial_transform = p_task->skeleton->get_bone_global_pose(p_task->chain.chain_root.bone); + p_task->chain.chain_root.current_pos = p_task->chain.chain_root.initial_transform.origin; - update_chain(p_task->skeleton, &p_task->chain.chain_root); + make_goal(p_task, p_task->skeleton->get_global_transform().affine_inverse(), blending_delta); if (p_use_magnet && p_task->chain.middle_chain_item) { p_task->chain.magnet_position = p_task->chain.middle_chain_item->initial_transform.origin.lerp(p_magnet_position, blending_delta); @@ -301,7 +286,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove Transform new_bone_pose(ci->initial_transform); new_bone_pose.origin = ci->current_pos; - if (!ci->children.empty()) { + if (!ci->children.is_empty()) { /// Rotate basis const Vector3 initial_ori((ci->children[0].initial_transform.origin - ci->initial_transform.origin).normalized()); const Vector3 rot_axis(initial_ori.cross(ci->current_ori).normalized()); @@ -310,6 +295,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove const real_t rot_angle(Math::acos(CLAMP(initial_ori.dot(ci->current_ori), -1, 1))); new_bone_pose.basis.rotate(rot_axis, rot_angle); } + } else { // Set target orientation to tip if (override_tip_basis) { @@ -319,9 +305,13 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove } } + // IK should not affect scale, so undo any scaling + new_bone_pose.basis.orthonormalize(); + new_bone_pose.basis.scale(p_task->skeleton->get_bone_global_pose(ci->bone).basis.get_scale()); + p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0, true); - if (!ci->children.empty()) { + if (!ci->children.is_empty()) { ci = &ci->children.write[0]; } else { ci = nullptr; diff --git a/scene/3d/skeleton_ik_3d.h b/scene/3d/skeleton_ik_3d.h index 6c1db6dd33..c98f55804c 100644 --- a/scene/3d/skeleton_ik_3d.h +++ b/scene/3d/skeleton_ik_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,17 +52,14 @@ class FabrikInverseKinematic { // Bone info BoneId bone = -1; - PhysicalBone3D *pb = nullptr; - real_t length = 0; + real_t length = 0.0; /// Positions relative to root bone Transform initial_transform; Vector3 current_pos; // Direction from this bone to child Vector3 current_ori; - ChainItem() {} - ChainItem *find_child(const BoneId p_bone_id); ChainItem *add_child(const BoneId p_bone_id); }; @@ -80,7 +77,7 @@ class FabrikInverseKinematic { struct Chain { ChainItem chain_root; - ChainItem *middle_chain_item; + ChainItem *middle_chain_item = nullptr; Vector<ChainTip> tips; Vector3 magnet_position; }; @@ -109,8 +106,6 @@ private: /// Init a chain that starts from the root to tip static bool build_chain(Task *p_task, bool p_force_simple_chain = true); - static void update_chain(const Skeleton3D *p_sk, ChainItem *p_chain_item); - static void solve_simple(Task *p_task, bool p_solve_magnet); /// Special solvers that solve only chains with one end effector static void solve_simple_backwards(Chain &r_chain, bool p_solve_magnet); @@ -130,7 +125,7 @@ class SkeletonIK3D : public Node { StringName root_bone; StringName tip_bone; - real_t interpolation = 1; + real_t interpolation = 1.0; Transform target; NodePath target_node_path_override; bool override_tip_basis = true; diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp index d811b2e852..3fde4d6ef3 100644 --- a/scene/3d/soft_body_3d.cpp +++ b/scene/3d/soft_body_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,7 +37,6 @@ #include "scene/3d/collision_object_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/3d/skeleton_3d.h" -#include "servers/physics_server_3d.h" SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {} @@ -48,27 +47,28 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) { mesh = p_mesh; surface = p_surface; -#ifndef _MSC_VER -#warning Softbody is not working, needs to be redone considering that these functions no longer exist -#endif -#if 0 - const uint32_t surface_format = RS::get_singleton()->mesh_surface_get_format(mesh, surface); - const int surface_vertex_len = RS::get_singleton()->mesh_surface_get_array_len(mesh, p_surface); - const int surface_index_len = RS::get_singleton()->mesh_surface_get_array_index_len(mesh, p_surface); + + RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh, surface); + uint32_t surface_offsets[RS::ARRAY_MAX]; + uint32_t vertex_stride; + uint32_t attrib_stride; + uint32_t skin_stride; + RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, attrib_stride, skin_stride); - buffer = RS::get_singleton()->mesh_surface_get_array(mesh, surface); - stride = RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_format, surface_vertex_len, surface_index_len, surface_offsets); + buffer = surface_data.vertex_data; + stride = vertex_stride; offset_vertices = surface_offsets[RS::ARRAY_VERTEX]; offset_normal = surface_offsets[RS::ARRAY_NORMAL]; -#endif } void SoftBodyRenderingServerHandler::clear() { - if (mesh.is_valid()) { - buffer.resize(0); - } + buffer.resize(0); + stride = 0; + offset_vertices = 0; + offset_normal = 0; + surface = 0; mesh = RID(); } @@ -77,7 +77,7 @@ void SoftBodyRenderingServerHandler::open() { } void SoftBodyRenderingServerHandler::close() { - //write_buffer.release(); + write_buffer = nullptr; } void SoftBodyRenderingServerHandler::commit_changes() { @@ -245,13 +245,11 @@ bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, V return true; } -void SoftBody3D::_changed_callback(Object *p_changed, const char *p_prop) { +void SoftBody3D::_softbody_changed() { prepare_physics_server(); _reset_points_offsets(); #ifdef TOOLS_ENABLED - if (p_changed == this) { - update_configuration_warning(); - } + update_configuration_warning(); #endif } @@ -259,7 +257,9 @@ void SoftBody3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_WORLD: { if (Engine::get_singleton()->is_editor_hint()) { - add_change_receptor(this); + // I have no idea what this is supposed to do, it's really weird + // leaving for upcoming PK work on physics + //add_change_receptor(this); } RID space = get_world_3d()->get_space(); @@ -309,6 +309,8 @@ void SoftBody3D::_notification(int p_what) { } void SoftBody3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid); + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask); ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask); @@ -337,18 +339,9 @@ void SoftBody3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness); ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness); - ClassDB::bind_method(D_METHOD("set_areaAngular_stiffness", "areaAngular_stiffness"), &SoftBody3D::set_areaAngular_stiffness); - ClassDB::bind_method(D_METHOD("get_areaAngular_stiffness"), &SoftBody3D::get_areaAngular_stiffness); - - ClassDB::bind_method(D_METHOD("set_volume_stiffness", "volume_stiffness"), &SoftBody3D::set_volume_stiffness); - ClassDB::bind_method(D_METHOD("get_volume_stiffness"), &SoftBody3D::get_volume_stiffness); - ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient); ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient); - ClassDB::bind_method(D_METHOD("set_pose_matching_coefficient", "pose_matching_coefficient"), &SoftBody3D::set_pose_matching_coefficient); - ClassDB::bind_method(D_METHOD("get_pose_matching_coefficient"), &SoftBody3D::get_pose_matching_coefficient); - ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient); ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient); @@ -366,12 +359,9 @@ void SoftBody3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "areaAngular_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_areaAngular_stiffness", "get_areaAngular_stiffness"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volume_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_volume_stiffness", "get_volume_stiffness"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pose_matching_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_pose_matching_coefficient", "get_pose_matching_coefficient"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable"); } @@ -380,7 +370,7 @@ String SoftBody3D::get_configuration_warning() const { String warning = MeshInstance3D::get_configuration_warning(); if (get_mesh().is_null()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } @@ -389,7 +379,7 @@ String SoftBody3D::get_configuration_warning() const { Transform t = get_transform(); if ((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.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } @@ -612,34 +602,10 @@ real_t SoftBody3D::get_linear_stiffness() { return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid); } -void SoftBody3D::set_areaAngular_stiffness(real_t p_areaAngular_stiffness) { - PhysicsServer3D::get_singleton()->soft_body_set_areaAngular_stiffness(physics_rid, p_areaAngular_stiffness); -} - -real_t SoftBody3D::get_areaAngular_stiffness() { - return PhysicsServer3D::get_singleton()->soft_body_get_areaAngular_stiffness(physics_rid); -} - -void SoftBody3D::set_volume_stiffness(real_t p_volume_stiffness) { - PhysicsServer3D::get_singleton()->soft_body_set_volume_stiffness(physics_rid, p_volume_stiffness); -} - -real_t SoftBody3D::get_volume_stiffness() { - return PhysicsServer3D::get_singleton()->soft_body_get_volume_stiffness(physics_rid); -} - real_t SoftBody3D::get_pressure_coefficient() { return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid); } -void SoftBody3D::set_pose_matching_coefficient(real_t p_pose_matching_coefficient) { - PhysicsServer3D::get_singleton()->soft_body_set_pose_matching_coefficient(physics_rid, p_pose_matching_coefficient); -} - -real_t SoftBody3D::get_pose_matching_coefficient() { - return PhysicsServer3D::get_singleton()->soft_body_get_pose_matching_coefficient(physics_rid); -} - void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) { PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient); } @@ -768,7 +734,9 @@ void SoftBody3D::_reset_points_offsets() { PinnedPoint *w = pinned_points.ptrw(); for (int i = pinned_points.size() - 1; 0 <= i; --i) { if (!r[i].spatial_attachment) { - w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path)); + if (!r[i].spatial_attachment_path.is_empty() && has_node(r[i].spatial_attachment_path)) { + w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path)); + } } if (!r[i].spatial_attachment) { diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h index c59a0b3aa3..f98df39209 100644 --- a/scene/3d/soft_body_3d.h +++ b/scene/3d/soft_body_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,20 +32,21 @@ #define SOFT_PHYSICS_BODY_H #include "scene/3d/mesh_instance_3d.h" +#include "servers/physics_server_3d.h" class SoftBody3D; -class SoftBodyRenderingServerHandler { +class SoftBodyRenderingServerHandler : public RenderingServerHandler { friend class SoftBody3D; RID mesh; - int surface; + int surface = 0; Vector<uint8_t> buffer; - uint32_t stride; - uint32_t offset_vertices; - uint32_t offset_normal; + uint32_t stride = 0; + uint32_t offset_vertices = 0; + uint32_t offset_normal = 0; - uint8_t *write_buffer; + uint8_t *write_buffer = nullptr; private: SoftBodyRenderingServerHandler(); @@ -57,9 +58,9 @@ private: void commit_changes(); public: - void set_vertex(int p_vertex_id, const void *p_vector3); - void set_normal(int p_vertex_id, const void *p_vector3); - void set_aabb(const AABB &p_aabb); + void set_vertex(int p_vertex_id, const void *p_vector3) override; + void set_normal(int p_vertex_id, const void *p_vector3) override; + void set_aabb(const AABB &p_aabb) override; }; class SoftBody3D : public MeshInstance3D { @@ -91,13 +92,15 @@ private: bool pinned_points_cache_dirty = true; Ref<ArrayMesh> debug_mesh_cache; - class MeshInstance3D *debug_mesh; + class MeshInstance3D *debug_mesh = nullptr; - bool capture_input_on_drag; + bool capture_input_on_drag = false; bool ray_pickable = true; void _update_pickable(); + void _softbody_changed(); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -107,8 +110,6 @@ protected: bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value); bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const; - virtual void _changed_callback(Object *p_changed, const char *p_prop) override; - void _notification(int p_what); static void _bind_methods(); @@ -122,6 +123,8 @@ public: void prepare_physics_server(); void become_mesh_owner(); + RID get_physics_rid() const { return physics_rid; } + void set_collision_mask(uint32_t p_mask); uint32_t get_collision_mask() const; @@ -149,18 +152,9 @@ public: void set_linear_stiffness(real_t p_linear_stiffness); real_t get_linear_stiffness(); - void set_areaAngular_stiffness(real_t p_areaAngular_stiffness); - real_t get_areaAngular_stiffness(); - - void set_volume_stiffness(real_t p_volume_stiffness); - real_t get_volume_stiffness(); - void set_pressure_coefficient(real_t p_pressure_coefficient); real_t get_pressure_coefficient(); - void set_pose_matching_coefficient(real_t p_pose_matching_coefficient); - real_t get_pose_matching_coefficient(); - void set_damping_coefficient(real_t p_damping_coefficient); real_t get_damping_coefficient(); diff --git a/scene/3d/spring_arm_3d.cpp b/scene/3d/spring_arm_3d.cpp index 287d760db0..9518b47696 100644 --- a/scene/3d/spring_arm_3d.cpp +++ b/scene/3d/spring_arm_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -78,11 +78,11 @@ void SpringArm3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); } -float SpringArm3D::get_length() const { +real_t SpringArm3D::get_length() const { return spring_length; } -void SpringArm3D::set_length(float p_length) { +void SpringArm3D::set_length(real_t p_length) { if (is_inside_tree() && (Engine::get_singleton()->is_editor_hint() || get_tree()->is_debugging_collisions_hint())) { update_gizmo(); } @@ -106,11 +106,11 @@ uint32_t SpringArm3D::get_mask() { return mask; } -float SpringArm3D::get_margin() { +real_t SpringArm3D::get_margin() { return margin; } -void SpringArm3D::set_margin(float p_margin) { +void SpringArm3D::set_margin(real_t p_margin) { margin = p_margin; } @@ -126,7 +126,7 @@ void SpringArm3D::clear_excluded_objects() { excluded_objects.clear(); } -float SpringArm3D::get_hit_length() { +real_t SpringArm3D::get_hit_length() { return current_spring_length; } @@ -143,7 +143,7 @@ void SpringArm3D::process_spring() { PhysicsDirectSpaceState3D::RayResult r; bool intersected = get_world_3d()->get_direct_space_state()->intersect_ray(get_global_transform().origin, get_global_transform().origin + motion, r, excluded_objects, mask); if (intersected) { - float dist = get_global_transform().origin.distance_to(r.position); + real_t dist = get_global_transform().origin.distance_to(r.position); dist -= margin; motion_delta = dist / (spring_length); } diff --git a/scene/3d/spring_arm_3d.h b/scene/3d/spring_arm_3d.h index 7f6fe2f1a2..63505ab9d3 100644 --- a/scene/3d/spring_arm_3d.h +++ b/scene/3d/spring_arm_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,19 +38,19 @@ class SpringArm3D : public Node3D { Ref<Shape3D> shape; Set<RID> excluded_objects; - float spring_length = 1; - float current_spring_length = 0; + real_t spring_length = 1.0; + real_t current_spring_length = 0.0; bool keep_child_basis = false; uint32_t mask = 1; - float margin = 0.01; + real_t margin = 0.01; protected: void _notification(int p_what); static void _bind_methods(); public: - void set_length(float p_length); - float get_length() const; + void set_length(real_t p_length); + real_t get_length() const; void set_shape(Ref<Shape3D> p_shape); Ref<Shape3D> get_shape() const; void set_mask(uint32_t p_mask); @@ -58,9 +58,9 @@ public: void add_excluded_object(RID p_rid); bool remove_excluded_object(RID p_rid); void clear_excluded_objects(); - float get_hit_length(); - void set_margin(float p_margin); - float get_margin(); + real_t get_hit_length(); + void set_margin(real_t p_margin); + real_t get_margin(); SpringArm3D() {} diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 1d20a9cd3b..0be54e7243 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -339,24 +339,10 @@ void SpriteBase3D::_bind_methods() { } SpriteBase3D::SpriteBase3D() { - color_dirty = true; - centered = true; - hflip = false; - vflip = false; - parent_sprite = nullptr; - pI = nullptr; - for (int i = 0; i < FLAG_MAX; i++) { flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED; } - alpha_cut = ALPHA_CUT_DISABLED; - billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED; - axis = Vector3::AXIS_Z; - pixel_size = 0.01; - modulate = Color(1, 1, 1, 1); - pending_update = false; - opacity = 1.0; immediate = RenderingServer::get_singleton()->immediate_create(); set_base(immediate); } @@ -380,7 +366,7 @@ void Sprite3D::_draw() { } Rect2 base_rect; - if (region) { + if (region_enabled) { base_rect = region_rect; } else { base_rect = Rect2(0, 0, texture->get_width(), texture->get_height()); @@ -525,23 +511,24 @@ Ref<Texture2D> Sprite3D::get_texture() const { return texture; } -void Sprite3D::set_region(bool p_region) { - if (p_region == region) { +void Sprite3D::set_region_enabled(bool p_region_enabled) { + if (p_region_enabled == region_enabled) { return; } - region = p_region; + region_enabled = p_region_enabled; _queue_update(); + notify_property_list_changed(); } -bool Sprite3D::is_region() const { - return region; +bool Sprite3D::is_region_enabled() const { + return region_enabled; } void Sprite3D::set_region_rect(const Rect2 &p_region_rect) { bool changed = region_rect != p_region_rect; region_rect = p_region_rect; - if (region && changed) { + if (region_enabled && changed) { _queue_update(); } } @@ -557,8 +544,6 @@ void Sprite3D::set_frame(int p_frame) { _queue_update(); - _change_notify("frame"); - _change_notify("frame_coords"); emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -581,7 +566,7 @@ void Sprite3D::set_vframes(int p_amount) { ERR_FAIL_COND(p_amount < 1); vframes = p_amount; _queue_update(); - _change_notify(); + notify_property_list_changed(); } int Sprite3D::get_vframes() const { @@ -592,7 +577,7 @@ void Sprite3D::set_hframes(int p_amount) { ERR_FAIL_COND(p_amount < 1); hframes = p_amount; _queue_update(); - _change_notify(); + notify_property_list_changed(); } int Sprite3D::get_hframes() const { @@ -610,7 +595,7 @@ Rect2 Sprite3D::get_item_rect() const { Size2i s; - if (region) { + if (region_enabled) { s = region_rect.size; } else { s = texture->get_size(); @@ -639,14 +624,18 @@ void Sprite3D::_validate_property(PropertyInfo &property) const { if (property.name == "frame_coords") { property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } + + if (!region_enabled && property.name == "region_rect") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } } void Sprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite3D::set_texture); ClassDB::bind_method(D_METHOD("get_texture"), &Sprite3D::get_texture); - ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite3D::set_region); - ClassDB::bind_method(D_METHOD("is_region"), &Sprite3D::is_region); + ClassDB::bind_method(D_METHOD("set_region_enabled", "enabled"), &Sprite3D::set_region_enabled); + ClassDB::bind_method(D_METHOD("is_region_enabled"), &Sprite3D::is_region_enabled); ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite3D::set_region_rect); ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite3D::get_region_rect); @@ -670,14 +659,14 @@ void Sprite3D::_bind_methods() { 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_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region_enabled", "is_region_enabled"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_SIGNAL(MethodInfo("frame_changed")); } Sprite3D::Sprite3D() { - region = false; + region_enabled = false; frame = 0; vframes = 1; hframes = 1; @@ -703,7 +692,7 @@ void AnimatedSprite3D::_draw() { Ref<Texture2D> texture = frames->get_frame(animation, frame); if (!texture.is_valid()) { - return; //no texuture no life + return; //no texture no life } Vector2 tsize = texture->get_size(); if (tsize.x == 0 || tsize.y == 0) { @@ -904,12 +893,13 @@ void AnimatedSprite3D::_notification(int p_what) { } else { frame = fc - 1; } + emit_signal(SceneStringNames::get_singleton()->animation_finished); } else { frame++; } _queue_update(); - _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } float to_process = MIN(timeout, remaining); @@ -935,7 +925,7 @@ void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { set_frame(frame); } - _change_notify(); + notify_property_list_changed(); _reset_timeout(); _queue_update(); update_configuration_warning(); @@ -968,7 +958,7 @@ void AnimatedSprite3D::set_frame(int p_frame) { frame = p_frame; _reset_timeout(); _queue_update(); - _change_notify("frame"); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } @@ -1004,8 +994,6 @@ Rect2 AnimatedSprite3D::get_item_rect() const { void AnimatedSprite3D::_res_changed() { set_frame(frame); - _change_notify("frame"); - _change_notify("animation"); _queue_update(); } @@ -1062,7 +1050,7 @@ void AnimatedSprite3D::set_animation(const StringName &p_animation) { animation = p_animation; _reset_timeout(); set_frame(0); - _change_notify(); + notify_property_list_changed(); _queue_update(); } @@ -1074,7 +1062,7 @@ String AnimatedSprite3D::get_configuration_warning() const { String warning = SpriteBase3D::get_configuration_warning(); if (frames.is_null()) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -1101,6 +1089,7 @@ void AnimatedSprite3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame); ADD_SIGNAL(MethodInfo("frame_changed")); + ADD_SIGNAL(MethodInfo("animation_finished")); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); @@ -1109,8 +1098,4 @@ void AnimatedSprite3D::_bind_methods() { } AnimatedSprite3D::AnimatedSprite3D() { - frame = 0; - playing = false; - animation = "default"; - timeout = 0; } diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index cb8467aac6..b48660eb2d 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,8 +31,8 @@ #ifndef SPRITE_3D_H #define SPRITE_3D_H -#include "scene/2d/animated_sprite_2d.h" #include "scene/3d/visual_instance_3d.h" +#include "scene/resources/sprite_frames.h" class SpriteBase3D : public GeometryInstance3D { GDCLASS(SpriteBase3D, GeometryInstance3D); @@ -55,32 +55,32 @@ public: }; private: - bool color_dirty; + bool color_dirty = true; Color color_accum; - SpriteBase3D *parent_sprite; + SpriteBase3D *parent_sprite = nullptr; List<SpriteBase3D *> children; - List<SpriteBase3D *>::Element *pI; + List<SpriteBase3D *>::Element *pI = nullptr; - bool centered; + bool centered = true; Point2 offset; - bool hflip; - bool vflip; + bool hflip = false; + bool vflip = false; - Color modulate; - float opacity; + Color modulate = Color(1, 1, 1, 1); + float opacity = 1.0; - Vector3::Axis axis; - float pixel_size; + Vector3::Axis axis = Vector3::AXIS_Z; + float pixel_size = 0.01; AABB aabb; RID immediate; bool flags[FLAG_MAX]; - AlphaCutMode alpha_cut; - StandardMaterial3D::BillboardMode billboard_mode; - bool pending_update; + AlphaCutMode alpha_cut = ALPHA_CUT_DISABLED; + StandardMaterial3D::BillboardMode billboard_mode = StandardMaterial3D::BILLBOARD_DISABLED; + bool pending_update = false; void _im_update(); void _propagate_color_changed(); @@ -107,8 +107,8 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - void set_region(bool p_region); - bool is_region() const; + void set_region_enabled(bool p_region_enabled); + bool is_region_enabled() const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; @@ -147,7 +147,7 @@ class Sprite3D : public SpriteBase3D { GDCLASS(Sprite3D, SpriteBase3D); Ref<Texture2D> texture; - bool region; + bool region_enabled; Rect2 region_rect; int frame; @@ -167,8 +167,8 @@ public: void set_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_texture() const; - void set_region(bool p_region); - bool is_region() const; + void set_region_enabled(bool p_region_enabled); + bool is_region_enabled() const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; @@ -195,16 +195,16 @@ class AnimatedSprite3D : public SpriteBase3D { GDCLASS(AnimatedSprite3D, SpriteBase3D); Ref<SpriteFrames> frames; - bool playing; - StringName animation; - int frame; + bool playing = false; + StringName animation = "default"; + int frame = 0; - bool centered; + bool centered = true; - float timeout; + float timeout = 0.0; - bool hflip; - bool vflip; + bool hflip = 1; + bool vflip = 1; Color modulate; diff --git a/scene/3d/vehicle_body_3d.cpp b/scene/3d/vehicle_body_3d.cpp index e27307e75f..5b0b3b89d3 100644 --- a/scene/3d/vehicle_body_3d.cpp +++ b/scene/3d/vehicle_body_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -106,7 +106,7 @@ String VehicleWheel3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (!Object::cast_to<VehicleBody3D>(get_parent())) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -147,77 +147,77 @@ void VehicleWheel3D::_update(PhysicsDirectBodyState3D *s) { } } -void VehicleWheel3D::set_radius(float p_radius) { +void VehicleWheel3D::set_radius(real_t p_radius) { m_wheelRadius = p_radius; update_gizmo(); } -float VehicleWheel3D::get_radius() const { +real_t VehicleWheel3D::get_radius() const { return m_wheelRadius; } -void VehicleWheel3D::set_suspension_rest_length(float p_length) { +void VehicleWheel3D::set_suspension_rest_length(real_t p_length) { m_suspensionRestLength = p_length; update_gizmo(); } -float VehicleWheel3D::get_suspension_rest_length() const { +real_t VehicleWheel3D::get_suspension_rest_length() const { return m_suspensionRestLength; } -void VehicleWheel3D::set_suspension_travel(float p_length) { +void VehicleWheel3D::set_suspension_travel(real_t p_length) { m_maxSuspensionTravelCm = p_length / 0.01; } -float VehicleWheel3D::get_suspension_travel() const { +real_t VehicleWheel3D::get_suspension_travel() const { return m_maxSuspensionTravelCm * 0.01; } -void VehicleWheel3D::set_suspension_stiffness(float p_value) { +void VehicleWheel3D::set_suspension_stiffness(real_t p_value) { m_suspensionStiffness = p_value; } -float VehicleWheel3D::get_suspension_stiffness() const { +real_t VehicleWheel3D::get_suspension_stiffness() const { return m_suspensionStiffness; } -void VehicleWheel3D::set_suspension_max_force(float p_value) { +void VehicleWheel3D::set_suspension_max_force(real_t p_value) { m_maxSuspensionForce = p_value; } -float VehicleWheel3D::get_suspension_max_force() const { +real_t VehicleWheel3D::get_suspension_max_force() const { return m_maxSuspensionForce; } -void VehicleWheel3D::set_damping_compression(float p_value) { +void VehicleWheel3D::set_damping_compression(real_t p_value) { m_wheelsDampingCompression = p_value; } -float VehicleWheel3D::get_damping_compression() const { +real_t VehicleWheel3D::get_damping_compression() const { return m_wheelsDampingCompression; } -void VehicleWheel3D::set_damping_relaxation(float p_value) { +void VehicleWheel3D::set_damping_relaxation(real_t p_value) { m_wheelsDampingRelaxation = p_value; } -float VehicleWheel3D::get_damping_relaxation() const { +real_t VehicleWheel3D::get_damping_relaxation() const { return m_wheelsDampingRelaxation; } -void VehicleWheel3D::set_friction_slip(float p_value) { +void VehicleWheel3D::set_friction_slip(real_t p_value) { m_frictionSlip = p_value; } -float VehicleWheel3D::get_friction_slip() const { +real_t VehicleWheel3D::get_friction_slip() const { return m_frictionSlip; } -void VehicleWheel3D::set_roll_influence(float p_value) { +void VehicleWheel3D::set_roll_influence(real_t p_value) { m_rollInfluence = p_value; } -float VehicleWheel3D::get_roll_influence() const { +real_t VehicleWheel3D::get_roll_influence() const { return m_rollInfluence; } @@ -295,27 +295,27 @@ void VehicleWheel3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_relaxation"), "set_damping_relaxation", "get_damping_relaxation"); } -void VehicleWheel3D::set_engine_force(float p_engine_force) { +void VehicleWheel3D::set_engine_force(real_t p_engine_force) { m_engineForce = p_engine_force; } -float VehicleWheel3D::get_engine_force() const { +real_t VehicleWheel3D::get_engine_force() const { return m_engineForce; } -void VehicleWheel3D::set_brake(float p_brake) { +void VehicleWheel3D::set_brake(real_t p_brake) { m_brake = p_brake; } -float VehicleWheel3D::get_brake() const { +real_t VehicleWheel3D::get_brake() const { return m_brake; } -void VehicleWheel3D::set_steering(float p_steering) { +void VehicleWheel3D::set_steering(real_t p_steering) { m_steering = p_steering; } -float VehicleWheel3D::get_steering() const { +real_t VehicleWheel3D::get_steering() const { return m_steering; } @@ -335,39 +335,15 @@ bool VehicleWheel3D::is_used_as_steering() const { return steers; } -float VehicleWheel3D::get_skidinfo() const { +real_t VehicleWheel3D::get_skidinfo() const { return m_skidInfo; } -float VehicleWheel3D::get_rpm() const { +real_t VehicleWheel3D::get_rpm() const { return m_rpm; } VehicleWheel3D::VehicleWheel3D() { - steers = false; - engine_traction = false; - m_steering = real_t(0.); - m_engineForce = real_t(0.); - m_rotation = real_t(0.); - m_deltaRotation = real_t(0.); - m_brake = real_t(0.); - m_rollInfluence = real_t(0.1); - - m_suspensionRestLength = 0.15; - m_wheelRadius = 0.5; //0.28; - m_suspensionStiffness = 5.88; - m_wheelsDampingCompression = 0.83; - m_wheelsDampingRelaxation = 0.88; - m_frictionSlip = 10.5; - m_bIsFrontWheel = false; - m_maxSuspensionTravelCm = 500; - m_maxSuspensionForce = 6000; - - m_suspensionRelativeVelocity = 0; - m_clippedInvContactDotSuspension = 1.0; - m_raycastInfo.m_isInContact = false; - - body = nullptr; } void VehicleBody3D::_update_wheel_transform(VehicleWheel3D &wheel, PhysicsDirectBodyState3D *s) { @@ -431,7 +407,7 @@ real_t VehicleBody3D::_ray_cast(int p_idx, PhysicsDirectBodyState3D *s) { PhysicsDirectSpaceState3D *ss = s->get_space_state(); - bool col = ss->intersect_ray(source, target, rr, exclude); + bool col = ss->intersect_ray(source, target, rr, exclude, get_collision_mask()); wheel.m_raycastInfo.m_groundObject = nullptr; @@ -564,7 +540,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const Vector3 vel = vel1 - vel2; Basis b2trans; - float b2invmass = 0; + real_t b2invmass = 0; Vector3 b2lv; Vector3 b2av; Vector3 b2invinertia; //todo @@ -587,7 +563,7 @@ void VehicleBody3D::_resolve_single_bilateral(PhysicsDirectBodyState3D *s, const b2invmass); // FIXME: rel_vel assignment here is overwritten by the following assignment. - // What seems to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel); + // What seems to be intended in the next assignment is: rel_vel = normal.dot(rel_vel); // Investigate why. real_t rel_vel = jac.getRelativeVelocity( s->get_linear_velocity(), @@ -622,8 +598,8 @@ VehicleBody3D::btVehicleWheelContactPoint::btVehicleWheelContactPoint(PhysicsDir m_frictionPositionWorld(frictionPosWorld), m_frictionDirectionWorld(frictionDirectionWorld), m_maxImpulse(maxImpulse) { - float denom0 = 0; - float denom1 = 0; + real_t denom0 = 0; + real_t denom1 = 0; { Vector3 r0 = frictionPosWorld - s->get_transform().origin; @@ -831,7 +807,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) { state = Object::cast_to<PhysicsDirectBodyState3D>(p_state); - float step = state->get_step(); + real_t step = state->get_step(); for (int i = 0; i < wheels.size(); i++) { _update_wheel(i, state); @@ -891,7 +867,7 @@ void VehicleBody3D::_direct_state_changed(Object *p_state) { state = nullptr; } -void VehicleBody3D::set_engine_force(float p_engine_force) { +void VehicleBody3D::set_engine_force(real_t p_engine_force) { engine_force = p_engine_force; for (int i = 0; i < wheels.size(); i++) { VehicleWheel3D &wheelInfo = *wheels[i]; @@ -901,11 +877,11 @@ void VehicleBody3D::set_engine_force(float p_engine_force) { } } -float VehicleBody3D::get_engine_force() const { +real_t VehicleBody3D::get_engine_force() const { return engine_force; } -void VehicleBody3D::set_brake(float p_brake) { +void VehicleBody3D::set_brake(real_t p_brake) { brake = p_brake; for (int i = 0; i < wheels.size(); i++) { VehicleWheel3D &wheelInfo = *wheels[i]; @@ -913,11 +889,11 @@ void VehicleBody3D::set_brake(float p_brake) { } } -float VehicleBody3D::get_brake() const { +real_t VehicleBody3D::get_brake() const { return brake; } -void VehicleBody3D::set_steering(float p_steering) { +void VehicleBody3D::set_steering(real_t p_steering) { m_steeringValue = p_steering; for (int i = 0; i < wheels.size(); i++) { VehicleWheel3D &wheelInfo = *wheels[i]; @@ -927,7 +903,7 @@ void VehicleBody3D::set_steering(float p_steering) { } } -float VehicleBody3D::get_steering() const { +real_t VehicleBody3D::get_steering() const { return m_steeringValue; } @@ -948,16 +924,6 @@ void VehicleBody3D::_bind_methods() { } VehicleBody3D::VehicleBody3D() { - m_pitchControl = 0; - m_currentVehicleSpeedKmHour = real_t(0.); - m_steeringValue = real_t(0.); - - engine_force = 0; - brake = 0; - - state = nullptr; - ccd = false; - exclude.insert(get_rid()); //PhysicsServer3D::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); diff --git a/scene/3d/vehicle_body_3d.h b/scene/3d/vehicle_body_3d.h index 0b4b3a4440..860fa7e3b7 100644 --- a/scene/3d/vehicle_body_3d.h +++ b/scene/3d/vehicle_body_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,52 +42,52 @@ class VehicleWheel3D : public Node3D { Transform m_worldTransform; Transform local_xform; - bool engine_traction; - bool steers; + bool engine_traction = false; + bool steers = false; Vector3 m_chassisConnectionPointCS; //const Vector3 m_wheelDirectionCS; //const Vector3 m_wheelAxleCS; // const or modified by steering - real_t m_suspensionRestLength; - real_t m_maxSuspensionTravelCm; - real_t m_wheelRadius; + real_t m_suspensionRestLength = 0.15; + real_t m_maxSuspensionTravelCm = 500.0; + real_t m_wheelRadius = 0.5; - real_t m_suspensionStiffness; - real_t m_wheelsDampingCompression; - real_t m_wheelsDampingRelaxation; - real_t m_frictionSlip; - real_t m_maxSuspensionForce; - bool m_bIsFrontWheel; + real_t m_suspensionStiffness = 5.88; + real_t m_wheelsDampingCompression = 0.83; + real_t m_wheelsDampingRelaxation = 0.88; + real_t m_frictionSlip = 10.5; + real_t m_maxSuspensionForce = 6000.0; + bool m_bIsFrontWheel = false; - VehicleBody3D *body; + VehicleBody3D *body = nullptr; //btVector3 m_wheelAxleCS; // const or modified by steering ? - real_t m_steering; - real_t m_rotation; - real_t m_deltaRotation; - real_t m_rpm; - real_t m_rollInfluence; - real_t m_engineForce; - real_t m_brake; + real_t m_steering = 0.0; + real_t m_rotation = 0.0; + real_t m_deltaRotation = 0.0; + real_t m_rpm = 0.0; + real_t m_rollInfluence = 0.1; + real_t m_engineForce = 0.0; + real_t m_brake = 0.0; - real_t m_clippedInvContactDotSuspension; - real_t m_suspensionRelativeVelocity; + real_t m_clippedInvContactDotSuspension = 1.0; + real_t m_suspensionRelativeVelocity = 0.0; //calculated by suspension - real_t m_wheelsSuspensionForce; - real_t m_skidInfo; + real_t m_wheelsSuspensionForce = 0.0; + real_t m_skidInfo = 0.0; struct RaycastInfo { //set by raycaster Vector3 m_contactNormalWS; //contactnormal Vector3 m_contactPointWS; //raycast hitpoint - real_t m_suspensionLength; + real_t m_suspensionLength = 0.0; Vector3 m_hardPointWS; //raycast starting point Vector3 m_wheelDirectionWS; //direction in worldspace Vector3 m_wheelAxleWS; // axle in worldspace - bool m_isInContact; - PhysicsBody3D *m_groundObject; //could be general void* ptr + bool m_isInContact = false; + PhysicsBody3D *m_groundObject = nullptr; //could be general void* ptr } m_raycastInfo; void _update(PhysicsDirectBodyState3D *s); @@ -97,29 +97,29 @@ protected: static void _bind_methods(); public: - void set_radius(float p_radius); - float get_radius() const; + void set_radius(real_t p_radius); + real_t get_radius() const; - void set_suspension_rest_length(float p_length); - float get_suspension_rest_length() const; + void set_suspension_rest_length(real_t p_length); + real_t get_suspension_rest_length() const; - void set_suspension_travel(float p_length); - float get_suspension_travel() const; + void set_suspension_travel(real_t p_length); + real_t get_suspension_travel() const; - void set_suspension_stiffness(float p_value); - float get_suspension_stiffness() const; + void set_suspension_stiffness(real_t p_value); + real_t get_suspension_stiffness() const; - void set_suspension_max_force(float p_value); - float get_suspension_max_force() const; + void set_suspension_max_force(real_t p_value); + real_t get_suspension_max_force() const; - void set_damping_compression(float p_value); - float get_damping_compression() const; + void set_damping_compression(real_t p_value); + real_t get_damping_compression() const; - void set_damping_relaxation(float p_value); - float get_damping_relaxation() const; + void set_damping_relaxation(real_t p_value); + real_t get_damping_relaxation() const; - void set_friction_slip(float p_value); - float get_friction_slip() const; + void set_friction_slip(real_t p_value); + real_t get_friction_slip() const; void set_use_as_traction(bool p_enable); bool is_used_as_traction() const; @@ -129,21 +129,21 @@ public: bool is_in_contact() const; - void set_roll_influence(float p_value); - float get_roll_influence() const; + void set_roll_influence(real_t p_value); + real_t get_roll_influence() const; - float get_skidinfo() const; + real_t get_skidinfo() const; - float get_rpm() const; + real_t get_rpm() const; - void set_engine_force(float p_engine_force); - float get_engine_force() const; + void set_engine_force(real_t p_engine_force); + real_t get_engine_force() const; - void set_brake(float p_brake); - float get_brake() const; + void set_brake(real_t p_brake); + real_t get_brake() const; - void set_steering(float p_steering); - float get_steering() const; + void set_steering(real_t p_steering); + real_t get_steering() const; String get_configuration_warning() const override; @@ -153,12 +153,12 @@ public: class VehicleBody3D : public RigidBody3D { GDCLASS(VehicleBody3D, RigidBody3D); - float engine_force; - float brake; + real_t engine_force = 0.0; + real_t brake = 0.0; - real_t m_pitchControl; - real_t m_steeringValue; - real_t m_currentVehicleSpeedKmHour; + real_t m_pitchControl = 0.0; + real_t m_steeringValue = 0.0; + real_t m_currentVehicleSpeedKmHour = 0.0; Set<RID> exclude; @@ -168,12 +168,12 @@ class VehicleBody3D : public RigidBody3D { Vector<real_t> m_sideImpulse; struct btVehicleWheelContactPoint { - PhysicsDirectBodyState3D *m_s; - PhysicsBody3D *m_body1; + PhysicsDirectBodyState3D *m_s = nullptr; + PhysicsBody3D *m_body1 = nullptr; Vector3 m_frictionPositionWorld; Vector3 m_frictionDirectionWorld; - real_t m_jacDiagABInv; - real_t m_maxImpulse; + real_t m_jacDiagABInv = 0.0; + real_t m_maxImpulse = 0.0; btVehicleWheelContactPoint(PhysicsDirectBodyState3D *s, PhysicsBody3D *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse); }; @@ -195,14 +195,14 @@ class VehicleBody3D : public RigidBody3D { void _direct_state_changed(Object *p_state) override; public: - void set_engine_force(float p_engine_force); - float get_engine_force() const; + void set_engine_force(real_t p_engine_force); + real_t get_engine_force() const; - void set_brake(float p_brake); - float get_brake() const; + void set_brake(real_t p_brake); + real_t get_brake() const; - void set_steering(float p_steering); - float get_steering() const; + void set_steering(real_t p_steering); + real_t get_steering() const; VehicleBody3D(); }; diff --git a/scene/3d/velocity_tracker_3d.cpp b/scene/3d/velocity_tracker_3d.cpp index eba7d44c16..5b5cc06456 100644 --- a/scene/3d/velocity_tracker_3d.cpp +++ b/scene/3d/velocity_tracker_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -45,7 +45,7 @@ void VelocityTracker3D::update_position(const Vector3 &p_position) { if (physics_step) { ph.frame = Engine::get_singleton()->get_physics_frames(); } else { - ph.frame = Engine::get_singleton()->get_idle_frame_ticks(); + ph.frame = Engine::get_singleton()->get_frame_ticks(); } if (position_history_len == 0 || position_history[0].frame != ph.frame) { //in same frame, use latest @@ -72,7 +72,7 @@ Vector3 VelocityTracker3D::get_tracked_linear_velocity() const { uint64_t base = Engine::get_singleton()->get_physics_frames(); base_time = float(base - position_history[0].frame) / Engine::get_singleton()->get_iterations_per_second(); } else { - uint64_t base = Engine::get_singleton()->get_idle_frame_ticks(); + uint64_t base = Engine::get_singleton()->get_frame_ticks(); base_time = double(base - position_history[0].frame) / 1000000.0; } } @@ -109,7 +109,7 @@ void VelocityTracker3D::reset(const Vector3 &p_new_pos) { if (physics_step) { ph.frame = Engine::get_singleton()->get_physics_frames(); } else { - ph.frame = Engine::get_singleton()->get_idle_frame_ticks(); + ph.frame = Engine::get_singleton()->get_frame_ticks(); } position_history.write[0] = ph; @@ -128,6 +128,4 @@ void VelocityTracker3D::_bind_methods() { VelocityTracker3D::VelocityTracker3D() { position_history.resize(4); // should be configurable - position_history_len = 0; - physics_step = false; } diff --git a/scene/3d/velocity_tracker_3d.h b/scene/3d/velocity_tracker_3d.h index a7ab3dce4d..e971f4755a 100644 --- a/scene/3d/velocity_tracker_3d.h +++ b/scene/3d/velocity_tracker_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,13 +37,13 @@ class VelocityTracker3D : public Reference { GDCLASS(VelocityTracker3D, Reference); struct PositionHistory { - uint64_t frame; + uint64_t frame = 0; Vector3 position; }; - bool physics_step; + bool physics_step = false; Vector<PositionHistory> position_history; - int position_history_len; + int position_history_len = 0; protected: static void _bind_methods(); diff --git a/scene/3d/visibility_notifier_3d.cpp b/scene/3d/visibility_notifier_3d.cpp index 9f5c40caf4..471838b9d1 100644 --- a/scene/3d/visibility_notifier_3d.cpp +++ b/scene/3d/visibility_notifier_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -69,7 +69,6 @@ void VisibilityNotifier3D::set_aabb(const AABB &p_aabb) { get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb)); } - _change_notify("aabb"); update_gizmo(); } @@ -80,13 +79,16 @@ AABB VisibilityNotifier3D::get_aabb() const { void VisibilityNotifier3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_WORLD: { - get_world_3d()->_register_notifier(this, get_global_transform().xform(aabb)); + world = get_world_3d(); + ERR_FAIL_COND(!world.is_valid()); + world->_register_notifier(this, get_global_transform().xform(aabb)); } break; case NOTIFICATION_TRANSFORM_CHANGED: { - get_world_3d()->_update_notifier(this, get_global_transform().xform(aabb)); + world->_update_notifier(this, get_global_transform().xform(aabb)); } break; case NOTIFICATION_EXIT_WORLD: { - get_world_3d()->_remove_notifier(this); + ERR_FAIL_COND(!world.is_valid()); + world->_remove_notifier(this); } break; } } @@ -109,7 +111,6 @@ void VisibilityNotifier3D::_bind_methods() { } VisibilityNotifier3D::VisibilityNotifier3D() { - aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); set_notify_transform(true); } @@ -249,6 +250,4 @@ VisibilityEnabler3D::VisibilityEnabler3D() { for (int i = 0; i < ENABLER_MAX; i++) { enabler[i] = true; } - - visible = false; } diff --git a/scene/3d/visibility_notifier_3d.h b/scene/3d/visibility_notifier_3d.h index 35f6c02e83..9f7705067f 100644 --- a/scene/3d/visibility_notifier_3d.h +++ b/scene/3d/visibility_notifier_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,13 +33,15 @@ #include "scene/3d/node_3d.h" +class World3D; class Camera3D; class VisibilityNotifier3D : public Node3D { GDCLASS(VisibilityNotifier3D, Node3D); + Ref<World3D> world; Set<Camera3D *> cameras; - AABB aabb; + AABB aabb = AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); protected: virtual void _screen_enter() {} @@ -74,7 +76,7 @@ protected: virtual void _screen_enter() override; virtual void _screen_exit() override; - bool visible; + bool visible = false; void _find_nodes(Node *p_node); diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp index 0b70b0f920..394c67e873 100644 --- a/scene/3d/visual_instance_3d.cpp +++ b/scene/3d/visual_instance_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,7 +43,6 @@ void VisualInstance3D::_update_visibility() { return; } - _change_notify("visible"); RS::get_singleton()->instance_set_visible(get_instance(), is_visible_in_tree()); } @@ -135,7 +134,6 @@ RID VisualInstance3D::get_base() const { VisualInstance3D::VisualInstance3D() { instance = RenderingServer::get_singleton()->instance_create(); RenderingServer::get_singleton()->instance_attach_object_instance_id(instance, get_instance_id()); - layers = 1; set_notify_transform(true); } @@ -371,7 +369,7 @@ void GeometryInstance3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_gi_mode", "mode"), &GeometryInstance3D::set_gi_mode); ClassDB::bind_method(D_METHOD("get_gi_mode"), &GeometryInstance3D::get_gi_mode); - ClassDB::bind_method(D_METHOD("set_lod_bias", "p_bias"), &GeometryInstance3D::set_lod_bias); + ClassDB::bind_method(D_METHOD("set_lod_bias", "bias"), &GeometryInstance3D::set_lod_bias); ClassDB::bind_method(D_METHOD("get_lod_bias"), &GeometryInstance3D::get_lod_bias); ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &GeometryInstance3D::set_custom_aabb); @@ -412,17 +410,5 @@ void GeometryInstance3D::_bind_methods() { } GeometryInstance3D::GeometryInstance3D() { - lod_min_distance = 0; - lod_max_distance = 0; - lod_min_hysteresis = 0; - lod_max_hysteresis = 0; - - lod_bias = 1.0; - - gi_mode = GI_MODE_DISABLED; - lightmap_scale = LIGHTMAP_SCALE_1X; - - shadow_casting_setting = SHADOW_CASTING_SETTING_ON; - extra_cull_margin = 0; //RS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); } diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 0810b7b4ce..7fed8095ef 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,7 +42,7 @@ class VisualInstance3D : public Node3D { RID base; RID instance; - uint32_t layers; + uint32_t layers = 1; RID _get_visual_instance_rid() const; @@ -105,21 +105,21 @@ public: }; private: - ShadowCastingSetting shadow_casting_setting; + ShadowCastingSetting shadow_casting_setting = SHADOW_CASTING_SETTING_ON; Ref<Material> material_override; - float lod_min_distance; - float lod_max_distance; - float lod_min_hysteresis; - float lod_max_hysteresis; + float lod_min_distance = 0.0; + float lod_max_distance = 0.0; + float lod_min_hysteresis = 0.0; + float lod_max_hysteresis = 0.0; - float lod_bias; + float lod_bias = 1.0; mutable HashMap<StringName, Variant> instance_uniforms; mutable HashMap<StringName, StringName> instance_uniform_property_remap; - float extra_cull_margin; - LightmapScale lightmap_scale; - GIMode gi_mode; + float extra_cull_margin = 0.0; + LightmapScale lightmap_scale = LIGHTMAP_SCALE_1X; + GIMode gi_mode = GI_MODE_DISABLED; const StringName *_instance_uniform_get_remap(const StringName p_name) const; diff --git a/scene/3d/voxelizer.cpp b/scene/3d/voxelizer.cpp index c570fc7b7c..1b9ce0201f 100644 --- a/scene/3d/voxelizer.cpp +++ b/scene/3d/voxelizer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -151,7 +151,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co Vector2 uv; Vector3 lnormal; get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal); - if (lnormal == Vector3()) { //just in case normal as nor provided + if (lnormal == Vector3()) { //just in case normal is not provided lnormal = normal; } @@ -183,7 +183,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co Vector3 lnormal; Vector2 uv; get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal); - if (lnormal == Vector3()) { //just in case normal as nor provided + if (lnormal == Vector3()) { //just in case normal is not provided lnormal = normal; } @@ -294,7 +294,7 @@ void Voxelizer::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, co Vector<Color> Voxelizer::_get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add) { Vector<Color> ret; - if (p_image.is_null() || p_image->empty()) { + if (p_image.is_null() || p_image->is_empty()) { ret.resize(bake_texture_size * bake_texture_size); for (int i = 0; i < bake_texture_size * bake_texture_size; i++) { ret.write[i] = p_color_add; @@ -344,7 +344,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Image> img_albedo; if (albedo_tex.is_valid()) { - img_albedo = albedo_tex->get_data(); + img_albedo = albedo_tex->get_image(); mc.albedo = _get_bake_texture(img_albedo, mat->get_albedo(), Color(0, 0, 0)); // albedo texture, color is multiplicative } else { mc.albedo = _get_bake_texture(img_albedo, Color(1, 1, 1), mat->get_albedo()); // no albedo texture, color is additive @@ -358,7 +358,7 @@ Voxelizer::MaterialCache Voxelizer::_get_material_cache(Ref<Material> p_material Ref<Image> img_emission; if (emission_tex.is_valid()) { - img_emission = emission_tex->get_data(); + img_emission = emission_tex->get_image(); } if (mat->get_emission_operator() == StandardMaterial3D::EMISSION_OP_ADD) { @@ -1007,7 +1007,4 @@ Transform Voxelizer::get_to_cell_space_xform() const { } Voxelizer::Voxelizer() { - sorted = false; - color_scan_cell_width = 4; - bake_texture_size = 128; } diff --git a/scene/3d/voxelizer.h b/scene/3d/voxelizer.h index 3546fd7729..87f949e7db 100644 --- a/scene/3d/voxelizer.h +++ b/scene/3d/voxelizer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,35 +44,25 @@ private: struct Cell { uint32_t children[8]; - float albedo[3]; //albedo in RGB24 - float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) - float normal[3]; - uint32_t used_sides; - float alpha; //used for upsampling - uint16_t x; - uint16_t y; - uint16_t z; - uint16_t level; + float albedo[3] = {}; //albedo in RGB24 + float emission[3] = {}; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast) + float normal[3] = {}; + uint32_t used_sides = 0; + float alpha = 0.0; //used for upsampling + uint16_t x = 0; + uint16_t y = 0; + uint16_t z = 0; + uint16_t level = 0; Cell() { for (int i = 0; i < 8; i++) { children[i] = CHILD_EMPTY; } - - for (int i = 0; i < 3; i++) { - emission[i] = 0; - albedo[i] = 0; - normal[i] = 0; - } - alpha = 0; - used_sides = 0; - x = y = z = 0; - level = 0; } }; Vector<Cell> bake_cells; - int cell_subdiv; + int cell_subdiv = 0; struct CellSort { union { @@ -82,10 +72,10 @@ private: uint64_t x : 16; uint64_t level : 16; }; - uint64_t key; + uint64_t key = 0; }; - int32_t index; + int32_t index = 0; _FORCE_INLINE_ bool operator<(const CellSort &p_cell_sort) const { return key < p_cell_sort.key; @@ -101,16 +91,16 @@ private: Map<Ref<Material>, MaterialCache> material_cache; AABB original_bounds; AABB po2_bounds; - int axis_cell_size[3]; + int axis_cell_size[3] = {}; Transform to_cell_space; - int color_scan_cell_width; - int bake_texture_size; - float cell_size; + int color_scan_cell_width = 4; + int bake_texture_size = 128; + float cell_size = 0.0; - int max_original_cells; - int leaf_voxel_count; + int max_original_cells = 0; + int leaf_voxel_count = 0; Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add); MaterialCache _get_material_cache(Ref<Material> p_material); @@ -119,7 +109,7 @@ private: void _fixup_plot(int p_idx, int p_level); void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx); - bool sorted; + bool sorted = false; void _sort(); public: diff --git a/scene/3d/world_environment.cpp b/scene/3d/world_environment.cpp index 3c12d4991e..214ffd6bd5 100644 --- a/scene/3d/world_environment.cpp +++ b/scene/3d/world_environment.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,51 +35,69 @@ void WorldEnvironment::_notification(int p_what) { if (p_what == Node3D::NOTIFICATION_ENTER_WORLD || p_what == Node3D::NOTIFICATION_ENTER_TREE) { if (environment.is_valid()) { - if (get_viewport()->find_world_3d()->get_environment().is_valid()) { - WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world_3d()->set_environment(environment); add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_environment(); } if (camera_effects.is_valid()) { - if (get_viewport()->find_world_3d()->get_camera_effects().is_valid()) { - WARN_PRINT("World already has a camera effects (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world_3d()->set_camera_effects(camera_effects); add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_effects(); } } else if (p_what == Node3D::NOTIFICATION_EXIT_WORLD || p_what == Node3D::NOTIFICATION_EXIT_TREE) { - if (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() == environment) { - get_viewport()->find_world_3d()->set_environment(Ref<Environment>()); + if (environment.is_valid()) { remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_environment(); } - if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) { - get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); + if (camera_effects.is_valid()) { remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); + _update_current_camera_effects(); } } } -void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { - if (is_inside_tree() && environment.is_valid() && get_viewport()->find_world_3d()->get_environment() == environment) { +void WorldEnvironment::_update_current_environment() { + WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); + + if (first) { + get_viewport()->find_world_3d()->set_environment(first->environment); + } else { get_viewport()->find_world_3d()->set_environment(Ref<Environment>()); + } + get_tree()->call_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning"); +} + +void WorldEnvironment::_update_current_camera_effects() { + WorldEnvironment *first = Object::cast_to<WorldEnvironment>(get_tree()->get_first_node_in_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()))); + if (first) { + get_viewport()->find_world_3d()->set_camera_effects(first->camera_effects); + } else { + get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); + } + + get_tree()->call_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id()), "update_configuration_warning"); +} + +void WorldEnvironment::set_environment(const Ref<Environment> &p_environment) { + if (environment == p_environment) { + return; + } + if (is_inside_tree() && environment.is_valid()) { remove_from_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - //clean up } environment = p_environment; + if (is_inside_tree() && environment.is_valid()) { - if (get_viewport()->find_world_3d()->get_environment().is_valid()) { - WARN_PRINT("World already has an environment (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world_3d()->set_environment(environment); add_to_group("_world_environment_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } - update_configuration_warning(); + if (is_inside_tree()) { + _update_current_environment(); + } else { + update_configuration_warning(); + } } Ref<Environment> WorldEnvironment::get_environment() const { @@ -87,22 +105,24 @@ Ref<Environment> WorldEnvironment::get_environment() const { } void WorldEnvironment::set_camera_effects(const Ref<CameraEffects> &p_camera_effects) { + if (camera_effects == p_camera_effects) { + return; + } + if (is_inside_tree() && camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() == camera_effects) { - get_viewport()->find_world_3d()->set_camera_effects(Ref<CameraEffects>()); remove_from_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); - //clean up } camera_effects = p_camera_effects; if (is_inside_tree() && camera_effects.is_valid()) { - if (get_viewport()->find_world_3d()->get_camera_effects().is_valid()) { - WARN_PRINT("World already has an camera_effects (Another WorldEnvironment?), overriding."); - } - get_viewport()->find_world_3d()->set_camera_effects(camera_effects); add_to_group("_world_camera_effects_" + itos(get_viewport()->find_world_3d()->get_scenario().get_id())); } - update_configuration_warning(); + if (is_inside_tree()) { + _update_current_camera_effects(); + } else { + update_configuration_warning(); + } } Ref<CameraEffects> WorldEnvironment::get_camera_effects() const { @@ -113,7 +133,7 @@ String WorldEnvironment::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!environment.is_valid()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("WorldEnvironment requires its \"Environment\" property to contain an Environment to have a visible effect."); @@ -123,14 +143,18 @@ String WorldEnvironment::get_configuration_warning() const { 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 (environment.is_valid() && get_viewport()->find_world_3d()->get_environment() != environment) { + if (!warning.is_empty()) { + warning += "\n\n"; + } + warning += TTR("Only the first Environment has an effect in a scene (or set of instantiated scenes)."); + } - if (nodes.size() > 1) { - if (!warning.empty()) { + if (camera_effects.is_valid() && get_viewport()->find_world_3d()->get_camera_effects() != camera_effects) { + if (!warning.is_empty()) { warning += "\n\n"; } - warning += TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); + warning += TTR("Only the first CameraEffects has an effect in a scene (or set of instantiated scenes)."); } return warning; diff --git a/scene/3d/world_environment.h b/scene/3d/world_environment.h index 3fd3dc0b50..e3f28d6d6b 100644 --- a/scene/3d/world_environment.h +++ b/scene/3d/world_environment.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,6 +41,9 @@ class WorldEnvironment : public Node { Ref<Environment> environment; Ref<CameraEffects> camera_effects; + void _update_current_environment(); + void _update_current_camera_effects(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 5d48795dc1..7fed34c7c6 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -65,7 +65,7 @@ String XRCamera3D::get_configuration_warning() const { // must be child node of XROrigin3D! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("XRCamera3D must have an XROrigin3D node as its parent."); @@ -91,9 +91,9 @@ Vector3 XRCamera3D::project_local_ray_normal(const Point2 &p_pos) const { Vector2 cpos = get_viewport()->get_camera_coords(p_pos); Vector3 ray; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar()); + CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); Vector2 screen_he = cm.get_viewport_half_extents(); - ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_znear()).normalized(); + ray = Vector3(((cpos.x / viewport_size.width) * 2.0 - 1.0) * screen_he.x, ((1.0 - (cpos.y / viewport_size.height)) * 2.0 - 1.0) * screen_he.y, -get_near()).normalized(); return ray; }; @@ -113,7 +113,7 @@ Point2 XRCamera3D::unproject_position(const Vector3 &p_pos) const { Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar()); + CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); Plane p(get_camera_transform().xform_inv(p_pos), 1.0); @@ -142,7 +142,7 @@ Vector3 XRCamera3D::project_position(const Point2 &p_point, float p_z_depth) con Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar()); + CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); Vector2 vp_he = cm.get_viewport_half_extents(); @@ -170,7 +170,7 @@ Vector<Plane> XRCamera3D::get_frustum() const { ERR_FAIL_COND_V(!is_inside_world(), Vector<Plane>()); Size2 viewport_size = get_viewport()->get_visible_rect().size; - CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_znear(), get_zfar()); + CameraMatrix cm = xr_interface->get_projection_for_eye(XRInterface::EYE_MONO, viewport_size.aspect(), get_near(), get_far()); return cm.get_projection_planes(get_camera_transform()); }; @@ -372,14 +372,14 @@ String XRController3D::get_configuration_warning() const { // must be child node of XROrigin! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("XRController3D must have an XROrigin3D node as its parent."); }; if (controller_id == 0) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."); @@ -497,14 +497,14 @@ String XRAnchor3D::get_configuration_warning() const { // must be child node of XROrigin3D! XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent()); if (origin == nullptr) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("XRAnchor3D must have an XROrigin3D node as its parent."); }; if (anchor_id == 0) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."); @@ -536,7 +536,7 @@ String XROrigin3D::get_configuration_warning() const { String warning = Node3D::get_configuration_warning(); if (tracked_camera == nullptr) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("XROrigin3D requires an XRCamera3D child node."); diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 6aa7709485..7cd6e2ac57 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index e426e98def..15f562242f 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -311,14 +311,6 @@ AnimationNodeBlendSpace1D::AnimationNodeBlendSpace1D() { for (int i = 0; i < MAX_BLEND_POINTS; i++) { blend_points[i].name = itos(i); } - blend_points_used = 0; - max_space = 1; - min_space = -1; - - snap = 0.1; - value_label = "value"; - - blend_position = "blend_position"; } AnimationNodeBlendSpace1D::~AnimationNodeBlendSpace1D() { diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index 816d3c9d4e..8886e6c679 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,24 +43,24 @@ class AnimationNodeBlendSpace1D : public AnimationRootNode { struct BlendPoint { StringName name; Ref<AnimationRootNode> node; - float position; + float position = 0.0; }; BlendPoint blend_points[MAX_BLEND_POINTS]; - int blend_points_used; + int blend_points_used = 0; - float max_space; - float min_space; + float max_space = 1.0; + float min_space = -1.0; - float snap; + float snap = 0.1; - String value_label; + String value_label = "value"; void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); void _tree_changed(); - StringName blend_position; + StringName blend_position = "blend_position"; protected: virtual void _validate_property(PropertyInfo &property) const override; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index 5a42e2af7a..9c4bc107dd 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -437,7 +437,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { Vector2 blend_pos = get_parameter(blend_position); int closest = get_parameter(this->closest); float length_internal = get_parameter(this->length_internal); - float mind = 0; //time of min distance point + float mind = 0.0; //time of min distance point if (blend_mode == BLEND_MODE_INTERPOLATED) { if (triangles.size() == 0) { @@ -529,7 +529,7 @@ float AnimationNodeBlendSpace2D::process(float p_time, bool p_seek) { } if (new_closest != closest && new_closest != -1) { - float from = 0; + float from = 0.0; if (blend_mode == BLEND_MODE_DISCRETE_CARRY && closest != -1) { //see how much animation remains from = blend_node(blend_points[closest].name, blend_points[closest].node, p_time, true, 0.0, FILTER_IGNORE, false) - length_internal; @@ -665,18 +665,6 @@ AnimationNodeBlendSpace2D::AnimationNodeBlendSpace2D() { for (int i = 0; i < MAX_BLEND_POINTS; i++) { blend_points[i].name = itos(i); } - auto_triangles = true; - blend_points_used = 0; - max_space = Vector2(1, 1); - min_space = Vector2(-1, -1); - snap = Vector2(0.1, 0.1); - x_label = "x"; - y_label = "y"; - trianges_dirty = false; - blend_position = "blend_position"; - closest = "closest"; - length_internal = "length_internal"; - blend_mode = BLEND_MODE_INTERPOLATED; } AnimationNodeBlendSpace2D::~AnimationNodeBlendSpace2D() { diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 2aff678aad..65d09a550d 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -55,23 +55,23 @@ protected: }; BlendPoint blend_points[MAX_BLEND_POINTS]; - int blend_points_used; + int blend_points_used = 0; struct BlendTriangle { - int points[3]; + int points[3] = {}; }; Vector<BlendTriangle> triangles; - StringName blend_position; - StringName closest; - StringName length_internal; - Vector2 max_space; - Vector2 min_space; - Vector2 snap; - String x_label; - String y_label; - BlendMode blend_mode; + StringName blend_position = "blend_position"; + StringName closest = "closest"; + StringName length_internal = "length_internal"; + Vector2 max_space = Vector2(1, 1); + Vector2 min_space = Vector2(-1, -1); + Vector2 snap = Vector2(0.1, 0.1); + String x_label = "x"; + String y_label = "y"; + BlendMode blend_mode = BLEND_MODE_INTERPOLATED; void _add_blend_point(int p_index, const Ref<AnimationRootNode> &p_node); void _set_triangles(const Vector<int> &p_triangles); @@ -79,8 +79,8 @@ protected: void _blend_triangle(const Vector2 &p_pos, const Vector2 *p_points, float *r_weights); - bool auto_triangles; - bool trianges_dirty; + bool auto_triangles = true; + bool trianges_dirty = false; void _update_triangles(); void _queue_auto_triangles(); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 56995c0c13..79a1dc1ac0 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,7 +34,6 @@ void AnimationNodeAnimation::set_animation(const StringName &p_name) { animation = p_name; - _change_notify("animation"); } StringName AnimationNodeAnimation::get_animation() const { @@ -125,9 +124,6 @@ void AnimationNodeAnimation::_bind_methods() { } AnimationNodeAnimation::AnimationNodeAnimation() { - last_version = 0; - skip = false; - time = "time"; } //////////////////////////////////////////////////////// @@ -346,21 +342,6 @@ void AnimationNodeOneShot::_bind_methods() { AnimationNodeOneShot::AnimationNodeOneShot() { add_input("in"); add_input("shot"); - - fade_in = 0.1; - fade_out = 0.1; - autorestart = false; - autorestart_delay = 1; - autorestart_random_delay = 0; - - mix = MIX_MODE_BLEND; - sync = false; - - active = "active"; - prev_active = "prev_active"; - time = "time"; - remaining = "remaining"; - time_to_restart = "time_to_restart"; } //////////////////////////////////////////////// @@ -405,10 +386,8 @@ void AnimationNodeAdd2::_bind_methods() { } AnimationNodeAdd2::AnimationNodeAdd2() { - add_amount = "add_amount"; add_input("in"); add_input("add"); - sync = false; } //////////////////////////////////////////////// @@ -454,11 +433,9 @@ void AnimationNodeAdd3::_bind_methods() { } AnimationNodeAdd3::AnimationNodeAdd3() { - add_amount = "add_amount"; add_input("-add"); add_input("in"); add_input("+add"); - sync = false; } ///////////////////////////////////////////// @@ -504,10 +481,8 @@ void AnimationNodeBlend2::_bind_methods() { } AnimationNodeBlend2::AnimationNodeBlend2() { - blend_amount = "blend_amount"; add_input("in"); add_input("blend"); - sync = false; } ////////////////////////////////////// @@ -583,7 +558,6 @@ void AnimationNodeTimeScale::_bind_methods() { } AnimationNodeTimeScale::AnimationNodeTimeScale() { - scale = "scale"; add_input("in"); } @@ -608,7 +582,6 @@ float AnimationNodeTimeSeek::process(float p_time, bool p_seek) { } else if (seek_pos >= 0) { float ret = blend_input(0, seek_pos, true, 1.0, FILTER_IGNORE, false); set_parameter(this->seek_pos, -1.0); //reset - _change_notify("seek_pos"); return ret; } else { return blend_input(0, p_time, false, 1.0, FILTER_IGNORE, false); @@ -620,7 +593,6 @@ void AnimationNodeTimeSeek::_bind_methods() { AnimationNodeTimeSeek::AnimationNodeTimeSeek() { add_input("in"); - seek_pos = "seek_position"; } ///////////////////////////////////////////////// @@ -728,7 +700,7 @@ float AnimationNodeTransition::process(float p_time, bool p_seek) { return 0; } - float rem = 0; + float rem = 0.0; if (prev < 0) { // process current animation, check for transition @@ -811,16 +783,7 @@ void AnimationNodeTransition::_bind_methods() { } AnimationNodeTransition::AnimationNodeTransition() { - prev_xfading = "prev_xfading"; - prev = "prev"; - time = "time"; - current = "current"; - prev_current = "prev_current"; - xfade = 0.0; - - enabled_inputs = 0; for (int i = 0; i < MAX_INPUTS; i++) { - inputs[i].auto_advance = false; inputs[i].name = "state " + itos(i); } } @@ -1158,6 +1121,13 @@ void AnimationNodeBlendTree::_get_property_list(List<PropertyInfo> *p_list) cons p_list->push_back(PropertyInfo(Variant::ARRAY, "node_connections", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } +void AnimationNodeBlendTree::reset_state() { + graph_offset = Vector2(); + nodes.clear(); + emit_changed(); + emit_signal("tree_changed"); +} + void AnimationNodeBlendTree::_tree_changed() { emit_signal("tree_changed"); } diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index 7241a6bc13..d82658c8c2 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,10 +37,10 @@ class AnimationNodeAnimation : public AnimationRootNode { GDCLASS(AnimationNodeAnimation, AnimationRootNode); StringName animation; - StringName time; + StringName time = "time"; - uint64_t last_version; - bool skip; + uint64_t last_version = 0; + bool skip = false; protected: void _validate_property(PropertyInfo &property) const override; @@ -71,26 +71,26 @@ public: }; private: - float fade_in; - float fade_out; + float fade_in = 0.1; + float fade_out = 0.1; - bool autorestart; - float autorestart_delay; - float autorestart_random_delay; - MixMode mix; + bool autorestart = false; + float autorestart_delay = 1.0; + float autorestart_random_delay = 0.0; + MixMode mix = MIX_MODE_BLEND; - bool sync; + bool sync = false; /* bool active; bool do_start; float time; float remaining;*/ - StringName active; - StringName prev_active; - StringName time; - StringName remaining; - StringName time_to_restart; + StringName active = "active"; + StringName prev_active = "prev_active"; + StringName time = "time"; + StringName remaining = "remaining"; + StringName time_to_restart = "time_to_restart"; protected: static void _bind_methods(); @@ -132,8 +132,8 @@ VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode) class AnimationNodeAdd2 : public AnimationNode { GDCLASS(AnimationNodeAdd2, AnimationNode); - StringName add_amount; - bool sync; + StringName add_amount = "add_amount"; + bool sync = false; protected: static void _bind_methods(); @@ -156,8 +156,8 @@ public: class AnimationNodeAdd3 : public AnimationNode { GDCLASS(AnimationNodeAdd3, AnimationNode); - StringName add_amount; - bool sync; + StringName add_amount = "add_amount"; + bool sync = false; protected: static void _bind_methods(); @@ -180,8 +180,8 @@ public: class AnimationNodeBlend2 : public AnimationNode { GDCLASS(AnimationNodeBlend2, AnimationNode); - StringName blend_amount; - bool sync; + StringName blend_amount = "blend_amount"; + bool sync = false; protected: static void _bind_methods(); @@ -225,7 +225,7 @@ public: class AnimationNodeTimeScale : public AnimationNode { GDCLASS(AnimationNodeTimeScale, AnimationNode); - StringName scale; + StringName scale = "scale"; protected: static void _bind_methods(); @@ -244,7 +244,7 @@ public: class AnimationNodeTimeSeek : public AnimationNode { GDCLASS(AnimationNodeTimeSeek, AnimationNode); - StringName seek_pos; + StringName seek_pos = "seek_position"; protected: static void _bind_methods(); @@ -268,12 +268,11 @@ class AnimationNodeTransition : public AnimationNode { }; struct InputData { String name; - bool auto_advance; - InputData() { auto_advance = false; } + bool auto_advance = false; }; InputData inputs[MAX_INPUTS]; - int enabled_inputs; + int enabled_inputs = 0; /* float prev_xfading; @@ -282,13 +281,13 @@ class AnimationNodeTransition : public AnimationNode { int current; int prev_current; */ - StringName prev_xfading; - StringName prev; - StringName time; - StringName current; - StringName prev_current; + StringName prev_xfading = "prev_xfading"; + StringName prev = "prev"; + StringName time = "time"; + StringName current = "current"; + StringName prev_current = "prev_current"; - float xfade; + float xfade = 0.0; void _update_inputs(); @@ -352,6 +351,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + public: enum ConnectionError { CONNECTION_OK, @@ -381,7 +382,7 @@ public: struct NodeConnection { StringName input_node; - int input_index; + int input_index = 0; StringName output_node; }; diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index abb2cf1b65..689acdd57b 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -308,7 +308,4 @@ void AnimationCache::set_root(Node *p_root) { } AnimationCache::AnimationCache() { - root = nullptr; - cache_dirty = true; - cache_valid = false; } diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h index feff1d364a..07c9d09ae0 100644 --- a/scene/animation/animation_cache.h +++ b/scene/animation/animation_cache.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,31 +39,23 @@ class AnimationCache : public Object { struct Path { RES resource; - Object *object; - Skeleton3D *skeleton; // haxor - Node *node; - Node3D *spatial; + Object *object = nullptr; + Skeleton3D *skeleton = nullptr; // haxor + Node *node = nullptr; + Node3D *spatial = nullptr; - int bone_idx; + int bone_idx = -1; Vector<StringName> subpath; - bool valid; - Path() { - object = nullptr; - skeleton = nullptr; - node = nullptr; - bone_idx = -1; - valid = false; - spatial = nullptr; - } + bool valid = false; }; Set<Node *> connected_nodes; Vector<Path> path_cache; - Node *root; + Node *root = nullptr; Ref<Animation> animation; - bool cache_dirty; - bool cache_valid; + bool cache_dirty = true; + bool cache_valid = false; void _node_exit_tree(Node *p_node); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 36552c966d..d46f24752e 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -130,11 +130,6 @@ void AnimationNodeStateMachineTransition::_bind_methods() { } AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() { - switch_mode = SWITCH_MODE_IMMEDIATE; - auto_advance = false; - xfade = 0; - disabled = false; - priority = 1; } //////////////////////////////////////////////////////// @@ -322,7 +317,7 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_st // stopped, invalid state String node_name = start_request; start_request = StringName(); //clear start request - ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing."); + ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?"); } } else { if (!_travel(p_state_machine, start_request)) { @@ -398,7 +393,7 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_st //find next StringName next; - float next_xfade = 0; + float next_xfade = 0.0; AnimationNodeStateMachineTransition::SwitchMode switch_mode = AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE; if (path.size()) { @@ -495,21 +490,13 @@ void AnimationNodeStateMachinePlayback::_bind_methods() { ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop); ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing); ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node); + ClassDB::bind_method(D_METHOD("get_current_play_position"), &AnimationNodeStateMachinePlayback::get_current_play_pos); + ClassDB::bind_method(D_METHOD("get_current_length"), &AnimationNodeStateMachinePlayback::get_current_length); ClassDB::bind_method(D_METHOD("get_travel_path"), &AnimationNodeStateMachinePlayback::get_travel_path); } AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() { set_local_to_scene(true); //only one per instanced scene - - playing = false; - len_current = 0; - fading_time = 0; - stop_request = false; - len_total = 0.0; - pos_current = 0.0; - loops_current = 0; - fading_pos = 0.0; - start_request_travel = false; } /////////////////////////////////////////////////////// @@ -927,6 +914,18 @@ void AnimationNodeStateMachine::_get_property_list(List<PropertyInfo> *p_list) c p_list->push_back(PropertyInfo(Variant::VECTOR2, "graph_offset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR)); } +void AnimationNodeStateMachine::reset_state() { + states.clear(); + transitions.clear(); + playback = "playback"; + start_node = StringName(); + end_node = StringName(); + graph_offset = Vector2(); + + emit_changed(); + emit_signal("tree_changed"); +} + void AnimationNodeStateMachine::set_node_position(const StringName &p_name, const Vector2 &p_position) { ERR_FAIL_COND(!states.has(p_name)); states[p_name].position = p_position; @@ -973,5 +972,4 @@ void AnimationNodeStateMachine::_bind_methods() { } AnimationNodeStateMachine::AnimationNodeStateMachine() { - playback = "playback"; } diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index ae8975e940..9c1bca63c3 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,13 +44,13 @@ public: }; private: - SwitchMode switch_mode; - bool auto_advance; + SwitchMode switch_mode = SWITCH_MODE_IMMEDIATE; + bool auto_advance = false; StringName advance_condition; StringName advance_condition_name; - float xfade; - bool disabled; - int priority; + float xfade = 0.0; + bool disabled = false; + int priority = 1; protected: static void _bind_methods(); @@ -89,28 +89,28 @@ class AnimationNodeStateMachinePlayback : public Resource { friend class AnimationNodeStateMachine; struct AStarCost { - float distance; + float distance = 0.0; StringName prev; }; - float len_total; + float len_total = 0.0; - float len_current; - float pos_current; - int loops_current; + float len_current = 0.0; + float pos_current = 0.0; + int loops_current = 0; StringName current; StringName fading_from; - float fading_time; - float fading_pos; + float fading_time = 0.0; + float fading_pos = 0.0; Vector<StringName> path; - bool playing; + bool playing = false; StringName start_request; - bool start_request_travel; - bool stop_request; + bool start_request_travel = false; + bool stop_request = false; bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel); @@ -154,7 +154,7 @@ private: Vector<Transition> transitions; - StringName playback; + StringName playback = "playback"; StringName start_node; StringName end_node; @@ -171,6 +171,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + public: virtual void get_parameter_list(List<PropertyInfo> *r_list) const override; virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 159ccae130..0c1798a876 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -206,7 +206,7 @@ void AnimationPlayer::_notification(int p_what) { } } break; case NOTIFICATION_INTERNAL_PROCESS: { - if (animation_process_mode == ANIMATION_PROCESS_PHYSICS) { + if (process_callback == ANIMATION_PROCESS_PHYSICS) { break; } @@ -215,7 +215,7 @@ void AnimationPlayer::_notification(int p_what) { } } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - if (animation_process_mode == ANIMATION_PROCESS_IDLE) { + if (process_callback == ANIMATION_PROCESS_IDLE) { break; } @@ -229,13 +229,13 @@ void AnimationPlayer::_notification(int p_what) { } } -void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { +void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim, Node *p_root_override) { // Already cached? if (p_anim->node_cache.size() == p_anim->animation->get_track_count()) { return; } - Node *parent = get_node(root); + Node *parent = p_root_override ? p_root_override : get_node(root); ERR_FAIL_COND(!parent); @@ -605,7 +605,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float } if (p_seeked) { - //find whathever should be playing + //find whatever should be playing int idx = a->track_find_key(i, p_time); if (idx < 0) { continue; @@ -634,7 +634,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float nc->audio_playing = true; playing_caches.insert(nc); - if (len && end_ofs > 0) { //force a end at a time + if (len && end_ofs > 0) { //force an end at a time nc->audio_len = len - start_ofs - end_ofs; } else { nc->audio_len = 0; @@ -665,7 +665,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float nc->audio_playing = true; playing_caches.insert(nc); - if (len && end_ofs > 0) { //force a end at a time + if (len && end_ofs > 0) { //force an end at a time nc->audio_len = len - start_ofs - end_ofs; } else { nc->audio_len = 0; @@ -782,13 +782,13 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f delta = next_pos - cd.pos; // Fix delta (after determination of backwards because negative zero is lost here) if (&cd == &playback.current) { - if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) { + if (!backwards && cd.pos <= len && next_pos == len) { //playback finished end_reached = true; end_notify = cd.pos < len; // Notify only if not already at the end } - if (backwards && cd.pos >= 0 && next_pos == 0 /*&& playback.blend.empty()*/) { + if (backwards && cd.pos >= 0 && next_pos == 0) { //playback finished end_reached = true; end_notify = cd.pos > 0; // Notify only if not already at the beginning @@ -969,7 +969,7 @@ Error AnimationPlayer::add_animation(const StringName &p_name, const Ref<Animati } _ref_anim(p_animation); - _change_notify(); + notify_property_list_changed(); return OK; } @@ -981,7 +981,7 @@ void AnimationPlayer::remove_animation(const StringName &p_name) { animation_set.erase(p_name); clear_caches(); - _change_notify(); + notify_property_list_changed(); } void AnimationPlayer::_ref_anim(const Ref<Animation> &p_anim) { @@ -1039,7 +1039,7 @@ void AnimationPlayer::rename_animation(const StringName &p_name, const StringNam } clear_caches(); - _change_notify(); + notify_property_list_changed(); } bool AnimationPlayer::has_animation(const StringName &p_name) const { @@ -1132,7 +1132,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float Playback &c = playback; if (c.current.from) { - float blend_time = 0; + float blend_time = 0.0; // find if it can blend BlendKey bk; bk.from = c.current.from->name; @@ -1343,7 +1343,7 @@ void AnimationPlayer::_stop_playing_caches() { } void AnimationPlayer::_node_removed(Node *p_node) { - clear_caches(); // nodes contained here ar being removed, clear the caches + clear_caches(); // nodes contained here are being removed, clear the caches } void AnimationPlayer::clear_caches() { @@ -1403,8 +1403,8 @@ bool AnimationPlayer::is_reset_on_save_enabled() const { return reset_on_save; } -void AnimationPlayer::set_animation_process_mode(AnimationProcessMode p_mode) { - if (animation_process_mode == p_mode) { +void AnimationPlayer::set_process_callback(AnimationProcessCallback p_mode) { + if (process_callback == p_mode) { return; } @@ -1412,14 +1412,14 @@ void AnimationPlayer::set_animation_process_mode(AnimationProcessMode p_mode) { if (pr) { _set_process(false); } - animation_process_mode = p_mode; + process_callback = p_mode; if (pr) { _set_process(true); } } -AnimationPlayer::AnimationProcessMode AnimationPlayer::get_animation_process_mode() const { - return animation_process_mode; +AnimationPlayer::AnimationProcessCallback AnimationPlayer::get_process_callback() const { + return process_callback; } void AnimationPlayer::set_method_call_mode(AnimationMethodCallMode p_mode) { @@ -1435,7 +1435,7 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) { return; } - switch (animation_process_mode) { + switch (process_callback) { case ANIMATION_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break; @@ -1497,13 +1497,13 @@ void AnimationPlayer::get_argument_options(const StringName &p_function, int p_i } #ifdef TOOLS_ENABLED -Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values() { +Ref<AnimatedValuesBackup> AnimationPlayer::backup_animated_values(Node *p_root_override) { Ref<AnimatedValuesBackup> backup; if (!playback.current.from) { return backup; } - _ensure_node_caches(playback.current.from); + _ensure_node_caches(playback.current.from, p_root_override); backup.instance(); for (int i = 0; i < playback.current.from->node_cache.size(); i++) { @@ -1560,10 +1560,11 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) { AnimationPlayer *aux_player = memnew(AnimationPlayer); EditorNode::get_singleton()->add_child(aux_player); - aux_player->set_root(aux_player->get_path_to(root_node)); aux_player->add_animation("RESET", reset_anim); aux_player->set_assigned_animation("RESET"); - Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(); + // Forcing the use of the original root because the scene where original player belongs may be not the active one + Node *root = get_node(get_root()); + Ref<AnimatedValuesBackup> old_values = aux_player->backup_animated_values(root); aux_player->seek(0.0f, true); aux_player->queue_delete(); @@ -1636,8 +1637,8 @@ void AnimationPlayer::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_caches"), &AnimationPlayer::clear_caches); - ClassDB::bind_method(D_METHOD("set_animation_process_mode", "mode"), &AnimationPlayer::set_animation_process_mode); - ClassDB::bind_method(D_METHOD("get_animation_process_mode"), &AnimationPlayer::get_animation_process_mode); + ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &AnimationPlayer::set_process_callback); + ClassDB::bind_method(D_METHOD("get_process_callback"), &AnimationPlayer::get_process_callback); ClassDB::bind_method(D_METHOD("set_method_call_mode", "mode"), &AnimationPlayer::set_method_call_mode); ClassDB::bind_method(D_METHOD("get_method_call_mode"), &AnimationPlayer::get_method_call_mode); @@ -1657,7 +1658,7 @@ void AnimationPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position"); ADD_GROUP("Playback Options", "playback_"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_animation_process_mode", "get_animation_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale"); @@ -1677,23 +1678,7 @@ void AnimationPlayer::_bind_methods() { } AnimationPlayer::AnimationPlayer() { - accum_pass = 1; - cache_update_size = 0; - cache_update_prop_size = 0; - cache_update_bezier_size = 0; - speed_scale = 1; - end_reached = false; - end_notify = false; - reset_on_save = true; - animation_process_mode = ANIMATION_PROCESS_IDLE; - method_call_mode = ANIMATION_METHOD_CALL_DEFERRED; - processing = false; - default_blend_time = 0; root = SceneStringNames::get_singleton()->path_pp; - playing = false; - active = true; - playback.seeked = false; - playback.started = false; } AnimationPlayer::~AnimationPlayer() { diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 7f0d5630e1..2a1821c215 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,9 +41,9 @@ class AnimatedValuesBackup : public Reference { GDCLASS(AnimatedValuesBackup, Reference); struct Entry { - Object *object; + Object *object = nullptr; Vector<StringName> subpath; // Unused if bone - int bone_idx; // -1 if not a bone + int bone_idx = -1; // -1 if not a bone Variant value; }; Vector<Entry> entries; @@ -64,7 +64,7 @@ class AnimationPlayer : public Node { OBJ_CATEGORY("Animation Nodes"); public: - enum AnimationProcessMode { + enum AnimationProcessCallback { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, ANIMATION_PROCESS_MANUAL, @@ -118,8 +118,6 @@ private: Variant value_accum; uint64_t accum_pass = 0; Variant capture; - - PropertyAnim() {} }; Map<StringName, PropertyAnim> property_anim; @@ -130,8 +128,6 @@ private: float bezier_accum = 0.0; Object *object = nullptr; uint64_t accum_pass = 0; - - BezierAnim() {} }; Map<StringName, BezierAnim> bezier_anim; @@ -141,7 +137,7 @@ private: struct TrackNodeCacheKey { ObjectID id; - int bone_idx; + int bone_idx = -1; inline bool operator<(const TrackNodeCacheKey &p_right) const { if (id == p_right.id) { @@ -155,16 +151,16 @@ private: Map<TrackNodeCacheKey, TrackNodeCache> node_cache_map; TrackNodeCache *cache_update[NODE_CACHE_UPDATE_MAX]; - int cache_update_size; + int cache_update_size = 0; TrackNodeCache::PropertyAnim *cache_update_prop[NODE_CACHE_UPDATE_MAX]; - int cache_update_prop_size; + int cache_update_prop_size = 0; TrackNodeCache::BezierAnim *cache_update_bezier[NODE_CACHE_UPDATE_MAX]; - int cache_update_bezier_size; + int cache_update_bezier_size = 0; Set<TrackNodeCache *> playing_caches; - uint64_t accum_pass; - float speed_scale; - float default_blend_time; + uint64_t accum_pass = 1; + float speed_scale = 1.0; + float default_blend_time = 0.0; struct AnimationData { String name; @@ -183,54 +179,43 @@ private: Map<BlendKey, float> blend_times; struct PlaybackData { - AnimationData *from; - float pos; - float speed_scale; - - PlaybackData() { - pos = 0; - speed_scale = 1.0; - from = nullptr; - } + AnimationData *from = nullptr; + float pos = 0.0; + float speed_scale = 1.0; }; struct Blend { PlaybackData data; - float blend_time; - float blend_left; - - Blend() { - blend_left = 0; - blend_time = 0; - } + float blend_time = 0.0; + float blend_left = 0.0; }; struct Playback { List<Blend> blend; PlaybackData current; StringName assigned; - bool seeked; - bool started; + bool seeked = false; + bool started = false; } playback; List<StringName> queued; - bool end_reached; - bool end_notify; + bool end_reached = false; + bool end_notify = false; String autoplay; - bool reset_on_save; - AnimationProcessMode animation_process_mode; - AnimationMethodCallMode method_call_mode; - bool processing; - bool active; + bool reset_on_save = true; + AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE; + AnimationMethodCallMode method_call_mode = ANIMATION_METHOD_CALL_DEFERRED; + bool processing = false; + bool active = true; NodePath root; void _animation_process_animation(AnimationData *p_anim, float p_time, float p_delta, float p_interp, bool p_is_current = true, bool p_seeked = false, bool p_started = false); - void _ensure_node_caches(AnimationData *p_anim); + void _ensure_node_caches(AnimationData *p_anim, Node *p_root_override = nullptr); void _animation_process_data(PlaybackData &cd, float p_delta, float p_blend, bool p_seeked, bool p_started); void _animation_process2(float p_delta, bool p_started); void _animation_update_transforms(); @@ -257,7 +242,7 @@ private: void _set_process(bool p_process, bool p_force = false); - bool playing; + bool playing = false; protected: bool _set(const StringName &p_name, const Variant &p_value); @@ -313,8 +298,8 @@ public: void set_reset_on_save_enabled(bool p_enabled); bool is_reset_on_save_enabled() const; - void set_animation_process_mode(AnimationProcessMode p_mode); - AnimationProcessMode get_animation_process_mode() const; + void set_process_callback(AnimationProcessCallback p_mode); + AnimationProcessCallback get_process_callback() const; void set_method_call_mode(AnimationMethodCallMode p_mode); AnimationMethodCallMode get_method_call_mode() const; @@ -334,7 +319,7 @@ public: void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; #ifdef TOOLS_ENABLED - Ref<AnimatedValuesBackup> backup_animated_values(); + Ref<AnimatedValuesBackup> backup_animated_values(Node *p_root_override = nullptr); Ref<AnimatedValuesBackup> apply_reset(bool p_user_initiated = false); bool can_apply_reset() const; #endif @@ -343,7 +328,7 @@ public: ~AnimationPlayer(); }; -VARIANT_ENUM_CAST(AnimationPlayer::AnimationProcessMode); +VARIANT_ENUM_CAST(AnimationPlayer::AnimationProcessCallback); VARIANT_ENUM_CAST(AnimationPlayer::AnimationMethodCallMode); #endif diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2ef3ba87b2..4b4d3943c9 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,7 +40,7 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { Array parameters = get_script_instance()->call("get_parameter_list"); for (int i = 0; i < parameters.size(); i++) { Dictionary d = parameters[i]; - ERR_CONTINUE(d.empty()); + ERR_CONTINUE(d.is_empty()); r_list->push_back(PropertyInfo::from_dict(d)); } } @@ -158,7 +158,7 @@ float AnimationNode::blend_input(int p_input, float p_time, bool p_seek, float p Ref<AnimationNode> node = blend_tree->get_node(node_name); //inputs.write[p_input].last_pass = state->last_pass; - float activity = 0; + float activity = 0.0; float ret = _blend_node(node_name, blend_tree->get_node_connection_array(node_name), nullptr, node, p_time, p_seek, p_blend, p_filter, p_optimize, &activity); Vector<AnimationTree::Activity> *activity_ptr = state->tree->input_activity_map.getptr(base_path); @@ -441,9 +441,6 @@ void AnimationNode::_bind_methods() { } AnimationNode::AnimationNode() { - state = nullptr; - parent = nullptr; - filter_enabled = false; } //////////////////// @@ -476,7 +473,7 @@ void AnimationTree::set_active(bool p_active) { active = p_active; started = active; - if (process_mode == ANIMATION_PROCESS_IDLE) { + if (process_callback == ANIMATION_PROCESS_IDLE) { set_process_internal(active); } else { set_physics_process_internal(active); @@ -497,8 +494,8 @@ bool AnimationTree::is_active() const { return active; } -void AnimationTree::set_process_mode(AnimationProcessMode p_mode) { - if (process_mode == p_mode) { +void AnimationTree::set_process_callback(AnimationProcessCallback p_mode) { + if (process_callback == p_mode) { return; } @@ -507,15 +504,15 @@ void AnimationTree::set_process_mode(AnimationProcessMode p_mode) { set_active(false); } - process_mode = p_mode; + process_callback = p_mode; if (was_active) { set_active(true); } } -AnimationTree::AnimationProcessMode AnimationTree::get_process_mode() const { - return process_mode; +AnimationTree::AnimationProcessCallback AnimationTree::get_process_callback() const { + return process_callback; } void AnimationTree::_node_removed(Node *p_node) { @@ -820,6 +817,7 @@ void AnimationTree::_process_graph(float p_delta) { Ref<Animation> a = as.animation; float time = as.time; float delta = as.delta; + float weight = as.blend; bool seeked = as.seeked; for (int i = 0; i < a->get_track_count(); i++) { @@ -839,7 +837,7 @@ void AnimationTree::_process_graph(float p_delta) { ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count); - float blend = (*as.track_blends)[blend_idx]; + float blend = (*as.track_blends)[blend_idx] * weight; if (blend < CMP_EPSILON) { continue; //nothing to blend @@ -1011,7 +1009,7 @@ void AnimationTree::_process_graph(float p_delta) { TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); if (seeked) { - //find whathever should be playing + //find whatever should be playing int idx = a->track_find_key(i, time); if (idx < 0) { continue; @@ -1040,7 +1038,7 @@ void AnimationTree::_process_graph(float p_delta) { t->playing = true; playing_caches.insert(t); - if (len && end_ofs > 0) { //force a end at a time + if (len && end_ofs > 0) { //force an end at a time t->len = len - start_ofs - end_ofs; } else { t->len = 0; @@ -1071,7 +1069,7 @@ void AnimationTree::_process_graph(float p_delta) { t->playing = true; playing_caches.insert(t); - if (len && end_ofs > 0) { //force a end at a time + if (len && end_ofs > 0) { //force an end at a time t->len = len - start_ofs - end_ofs; } else { t->len = 0; @@ -1236,11 +1234,11 @@ void AnimationTree::advance(float p_time) { } void AnimationTree::_notification(int p_what) { - if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_mode == ANIMATION_PROCESS_PHYSICS) { + if (active && p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS && process_callback == ANIMATION_PROCESS_PHYSICS) { _process_graph(get_physics_process_delta_time()); } - if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_mode == ANIMATION_PROCESS_IDLE) { + if (active && p_what == NOTIFICATION_INTERNAL_PROCESS && process_callback == ANIMATION_PROCESS_IDLE) { _process_graph(get_process_delta_time()); } @@ -1287,14 +1285,14 @@ String AnimationTree::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!root.is_valid()) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("No root AnimationNode for the graph is set."); } if (!has_node(animation_player)) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("Path to an AnimationPlayer node containing animations is not set."); @@ -1302,12 +1300,12 @@ String AnimationTree::get_configuration_warning() const { AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); if (!player) { - if (!warning.empty()) { + if (!warning.is_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()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("The AnimationPlayer root node is not a valid node."); @@ -1339,6 +1337,7 @@ void AnimationTree::_tree_changed() { } void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<AnimationNode> node) { + ERR_FAIL_COND(node.is_null()); if (!property_parent_map.has(p_base_path)) { property_parent_map[p_base_path] = HashMap<StringName, StringName>(); } @@ -1396,7 +1395,7 @@ void AnimationTree::_update_properties() { properties_dirty = false; - _change_notify(); + notify_property_list_changed(); } bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) { @@ -1406,9 +1405,6 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) { if (property_map.has(p_name)) { property_map[p_name] = p_value; -#ifdef TOOLS_ENABLED - _change_notify(p_name.operator String().utf8().get_data()); -#endif return true; } @@ -1476,8 +1472,8 @@ void AnimationTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_tree_root", "root"), &AnimationTree::set_tree_root); ClassDB::bind_method(D_METHOD("get_tree_root"), &AnimationTree::get_tree_root); - ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &AnimationTree::set_process_mode); - ClassDB::bind_method(D_METHOD("get_process_mode"), &AnimationTree::get_process_mode); + ClassDB::bind_method(D_METHOD("set_process_callback", "mode"), &AnimationTree::set_process_callback); + ClassDB::bind_method(D_METHOD("get_process_callback"), &AnimationTree::get_process_callback); ClassDB::bind_method(D_METHOD("set_animation_player", "root"), &AnimationTree::set_animation_player); ClassDB::bind_method(D_METHOD("get_animation_player"), &AnimationTree::get_animation_player); @@ -1496,7 +1492,7 @@ void AnimationTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tree_root", PROPERTY_HINT_RESOURCE_TYPE, "AnimationRootNode"), "set_tree_root", "get_tree_root"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "anim_player", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "AnimationPlayer"), "set_animation_player", "get_animation_player"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "active"), "set_active", "is_active"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_mode", "get_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle,Manual"), "set_process_callback", "get_process_callback"); ADD_GROUP("Root Motion", "root_motion_"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_motion_track"), "set_root_motion_track", "get_root_motion_track"); @@ -1506,13 +1502,6 @@ void AnimationTree::_bind_methods() { } AnimationTree::AnimationTree() { - process_mode = ANIMATION_PROCESS_IDLE; - active = false; - cache_valid = false; - setup_pass = 1; - process_pass = 1; - started = true; - properties_dirty = true; } AnimationTree::~AnimationTree() { diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 166ca04f40..1c5aec26ab 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -63,26 +63,26 @@ public: struct AnimationState { Ref<Animation> animation; - float time; - float delta; - const Vector<float> *track_blends; - float blend; - bool seeked; + float time = 0.0; + float delta = 0.0; + const Vector<float> *track_blends = nullptr; + float blend = 0.0; + bool seeked = false; }; struct State { - int track_count; + int track_count = 0; HashMap<NodePath, int> track_map; List<AnimationState> animation_states; - bool valid; - AnimationPlayer *player; - AnimationTree *tree; + bool valid = false; + AnimationPlayer *player = nullptr; + AnimationTree *tree = nullptr; String invalid_reasons; - uint64_t last_pass; + uint64_t last_pass = 0; }; Vector<float> blends; - State *state; + State *state = nullptr; float _pre_process(const StringName &p_base_path, AnimationNode *p_parent, State *p_state, float p_time, bool p_seek, const Vector<StringName> &p_connections); void _pre_update_animations(HashMap<NodePath, int> *track_map); @@ -90,10 +90,10 @@ public: //all this is temporary StringName base_path; Vector<StringName> connections; - AnimationNode *parent; + AnimationNode *parent = nullptr; HashMap<NodePath, bool> filter; - bool filter_enabled; + bool filter_enabled = false; Array _get_filters() const; void _set_filters(const Array &p_filters); @@ -163,7 +163,7 @@ class AnimationTree : public Node { GDCLASS(AnimationTree, Node); public: - enum AnimationProcessMode { + enum AnimationProcessCallback { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, ANIMATION_PROCESS_MANUAL, @@ -171,36 +171,29 @@ public: private: struct TrackCache { - bool root_motion; - uint64_t setup_pass; - uint64_t process_pass; - Animation::TrackType type; - Object *object; + bool root_motion = false; + uint64_t setup_pass = 0; + uint64_t process_pass = 0; + Animation::TrackType type = Animation::TrackType::TYPE_ANIMATION; + Object *object = nullptr; ObjectID object_id; TrackCache() { - root_motion = false; - setup_pass = 0; - process_pass = 0; - object = nullptr; } virtual ~TrackCache() {} }; struct TrackCacheTransform : public TrackCache { - Node3D *spatial; - Skeleton3D *skeleton; - int bone_idx; + Node3D *spatial = nullptr; + Skeleton3D *skeleton = nullptr; + int bone_idx = -1; Vector3 loc; Quat rot; - float rot_blend_accum; + float rot_blend_accum = 0.0; Vector3 scale; TrackCacheTransform() { type = Animation::TYPE_TRANSFORM; - spatial = nullptr; - bone_idx = -1; - skeleton = nullptr; } }; @@ -215,33 +208,28 @@ private: }; struct TrackCacheBezier : public TrackCache { - float value; + float value = 0.0; Vector<StringName> subpath; TrackCacheBezier() { type = Animation::TYPE_BEZIER; - value = 0; } }; struct TrackCacheAudio : public TrackCache { - bool playing; - float start; - float len; + bool playing = false; + float start = 0.0; + float len = 0.0; TrackCacheAudio() { type = Animation::TYPE_AUDIO; - playing = false; - start = 0; - len = 0; } }; struct TrackCacheAnimation : public TrackCache { - bool playing; + bool playing = false; TrackCacheAnimation() { type = Animation::TYPE_ANIMATION; - playing = false; } }; @@ -250,12 +238,12 @@ private: Ref<AnimationNode> root; - AnimationProcessMode process_mode; - bool active; + AnimationProcessCallback process_callback = ANIMATION_PROCESS_IDLE; + bool active = false; NodePath animation_player; AnimationNode::State state; - bool cache_valid; + bool cache_valid = false; void _node_removed(Node *p_node); void _caches_cleared(); @@ -263,16 +251,16 @@ private: bool _update_caches(AnimationPlayer *player); void _process_graph(float p_delta); - uint64_t setup_pass; - uint64_t process_pass; + uint64_t setup_pass = 1; + uint64_t process_pass = 1; - bool started; + bool started = true; NodePath root_motion_track; Transform root_motion_transform; friend class AnimationNode; - bool properties_dirty; + bool properties_dirty = true; void _tree_changed(); void _update_properties(); List<PropertyInfo> properties; @@ -280,8 +268,8 @@ private: HashMap<StringName, Variant> property_map; struct Activity { - uint64_t last_pass; - float activity; + uint64_t last_pass = 0; + float activity = 0.0; }; HashMap<StringName, Vector<Activity>> input_activity_map; @@ -306,8 +294,8 @@ public: void set_active(bool p_active); bool is_active() const; - void set_process_mode(AnimationProcessMode p_mode); - AnimationProcessMode get_process_mode() const; + void set_process_callback(AnimationProcessCallback p_mode); + AnimationProcessCallback get_process_callback() const; void set_animation_player(const NodePath &p_player); NodePath get_animation_player() const; @@ -332,6 +320,6 @@ public: ~AnimationTree(); }; -VARIANT_ENUM_CAST(AnimationTree::AnimationProcessMode) +VARIANT_ENUM_CAST(AnimationTree::AnimationProcessCallback) #endif // ANIMATION_GRAPH_PLAYER_H diff --git a/scene/animation/root_motion_view.cpp b/scene/animation/root_motion_view.cpp index cbf2e4a6ff..9ee1f32581 100644 --- a/scene/animation/root_motion_view.cpp +++ b/scene/animation/root_motion_view.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -89,12 +89,12 @@ void RootMotionView::_notification(int p_what) { AnimationTree *tree = Object::cast_to<AnimationTree>(node); if (tree && tree->is_active() && tree->get_root_motion_track() != NodePath()) { - if (is_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_PHYSICS) { + if (is_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_PHYSICS) { set_process_internal(false); set_physics_process_internal(true); } - if (is_physics_processing_internal() && tree->get_process_mode() == AnimationTree::ANIMATION_PROCESS_IDLE) { + if (is_physics_processing_internal() && tree->get_process_callback() == AnimationTree::ANIMATION_PROCESS_IDLE) { set_process_internal(true); set_physics_process_internal(false); } @@ -188,13 +188,9 @@ void RootMotionView::_bind_methods() { } RootMotionView::RootMotionView() { - zero_y = true; - radius = 10; - cell_size = 1; set_process_internal(true); immediate = RenderingServer::get_singleton()->immediate_create(); set_base(immediate); - color = Color(0.5, 0.5, 1.0); } RootMotionView::~RootMotionView() { diff --git a/scene/animation/root_motion_view.h b/scene/animation/root_motion_view.h index 77c51fe47a..afcff6137f 100644 --- a/scene/animation/root_motion_view.h +++ b/scene/animation/root_motion_view.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,12 +39,12 @@ class RootMotionView : public VisualInstance3D { public: RID immediate; NodePath path; - float cell_size; - float radius; - bool use_in_game; - Color color; - bool first; - bool zero_y; + float cell_size = 1.0; + float radius = 10.0; + bool use_in_game = false; + Color color = Color(0.5, 0.5, 1.0); + bool first = true; + bool zero_y = true; Transform accumulated; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 1a2a97ada8..2030808724 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -869,8 +869,21 @@ void Tween::start() { return; } + pending_update++; + for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { + InterpolateData &data = E->get(); + data.active = true; + } + pending_update--; + // We want to be activated set_active(true); + + // Don't resume from current position if stop_all() function has been used + if (was_stopped) { + seek(0); + } + was_stopped = false; } void Tween::reset(Object *p_object, StringName p_key) { @@ -939,7 +952,7 @@ void Tween::stop(Object *p_object, StringName p_key) { void Tween::stop_all() { // We no longer need to be active since all tweens have been stopped set_active(false); - + was_stopped = true; // For each interpolation... pending_update++; for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { @@ -1098,11 +1111,11 @@ void Tween::seek(real_t p_time) { real_t Tween::tell() const { // We want to grab the position of the furthest along tween pending_update++; - real_t pos = 0; + real_t pos = 0.0; // For each interpolation... for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { - // Get the data and figure out if it's position is further along than the previous ones + // Get the data and figure out if its position is further along than the previous ones const InterpolateData &data = E->get(); if (data.elapsed > pos) { // Save it if so @@ -1122,7 +1135,7 @@ real_t Tween::get_runtime() const { pending_update++; // For each interpolation... - real_t runtime = 0; + real_t runtime = 0.0; for (const List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) { // Get the tween data and see if it's runtime is greater than the previous tweens const InterpolateData &data = E->get(); @@ -1350,6 +1363,9 @@ void Tween::interpolate_property(Object *p_object, NodePath p_property, Variant return; } + // Check that the target object is valid + ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); + // Get the property from the node path p_property = p_property.get_as_property_path(); @@ -1378,6 +1394,9 @@ void Tween::interpolate_method(Object *p_object, StringName p_method, Variant p_ return; } + // Check that the target object is valid + ERR_FAIL_COND_MSG(p_object == nullptr, vformat("The Tween \"%s\"'s target node is `null`. Is the node reference correct?", get_name())); + // Convert any integers into REALs as they are better for interpolation if (p_initial_val.get_type() == Variant::INT) { p_initial_val = p_initial_val.operator real_t(); @@ -1789,12 +1808,6 @@ void Tween::targeting_method(Object *p_object, StringName p_method, Object *p_in } Tween::Tween() { - // Initialize tween attributes - tween_process_mode = TWEEN_PROCESS_IDLE; - repeat = false; - speed_scale = 1; - pending_update = 0; - uid = 0; } Tween::~Tween() { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 822fcf0b6f..142c0c65e0 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -79,11 +79,11 @@ private: }; struct InterpolateData { - bool active; - InterpolateType type; - bool finish; - bool call_deferred; - real_t elapsed; + bool active = false; + InterpolateType type = INTER_CALLBACK; + bool finish = false; + bool call_deferred = false; + real_t elapsed = 0.0; ObjectID id; Vector<StringName> key; StringName concatenated_key; @@ -92,33 +92,28 @@ private: Variant final_val; ObjectID target_id; Vector<StringName> target_key; - real_t duration; - TransitionType trans_type; - EaseType ease_type; - real_t delay; - int args; + real_t duration = 0.0; + TransitionType trans_type = TransitionType::TRANS_BACK; + EaseType ease_type = EaseType::EASE_COUNT; + real_t delay = 0.0; + int args = 0; Variant arg[5]; - int uid; - InterpolateData() { - active = false; - finish = false; - call_deferred = false; - uid = 0; - } + int uid = 0; }; String autoplay; - TweenProcessMode tween_process_mode; - bool repeat; - float speed_scale; - mutable int pending_update; - int uid; + TweenProcessMode tween_process_mode = TWEEN_PROCESS_IDLE; + bool repeat = false; + float speed_scale = 1.0; + mutable int pending_update = 0; + int uid = 0; + bool was_stopped = false; List<InterpolateData> interpolates; struct PendingCommand { StringName key; - int args; + int args = 0; Variant arg[10]; }; List<PendingCommand> pending_commands; diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp index 14aae9c7bf..1478cbf69e 100644 --- a/scene/audio/audio_stream_player.cpp +++ b/scene/audio/audio_stream_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -99,37 +99,37 @@ void AudioStreamPlayer::_mix_audio() { use_fadeout = false; } - if (!stream_playback.is_valid() || !active || + if (!stream_playback.is_valid() || !active.is_set() || (stream_paused && !stream_paused_fade)) { return; } if (stream_paused) { - if (stream_paused_fade) { + if (stream_paused_fade && stream_playback->is_playing()) { _mix_internal(true); stream_paused_fade = false; } return; } - if (setstop) { + if (setstop.is_set()) { _mix_internal(true); stream_playback->stop(); - setstop = false; + setstop.clear(); } - if (setseek >= 0.0 && !stop_has_priority) { + if (setseek.get() >= 0.0 && !stop_has_priority.is_set()) { if (stream_playback->is_playing()) { //fade out to avoid pops _mix_internal(true); } - stream_playback->start(setseek); - setseek = -1.0; //reset seek + stream_playback->start(setseek.get()); + setseek.set(-1.0); //reset seek mix_volume_db = volume_db; //reset ramp } - stop_has_priority = false; + stop_has_priority.clear(); _mix_internal(false); } @@ -143,8 +143,8 @@ void AudioStreamPlayer::_notification(int p_what) { } if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (!active || (setseek < 0 && !stream_playback->is_playing())) { - active = false; + if (!active.is_set() || (setseek.get() < 0 && !stream_playback->is_playing())) { + active.clear(); set_process_internal(false); emit_signal("finished"); } @@ -169,9 +169,9 @@ void AudioStreamPlayer::_notification(int p_what) { void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { AudioServer::get_singleton()->lock(); - if (active && stream_playback.is_valid() && !stream_paused) { + if (active.is_set() && stream_playback.is_valid() && !stream_paused) { //changing streams out of the blue is not a great idea, but at least - //lets try to somehow avoid a click + //let's try to somehow avoid a click AudioFrame *buffer = fadeout_buffer.ptrw(); int buffer_size = fadeout_buffer.size(); @@ -196,9 +196,9 @@ void AudioStreamPlayer::set_stream(Ref<AudioStream> p_stream) { if (stream_playback.is_valid()) { stream_playback.unref(); stream.unref(); - active = false; - setseek = -1; - setstop = false; + active.clear(); + setseek.set(-1); + setstop.clear(); } if (p_stream.is_valid()) { @@ -237,29 +237,29 @@ float AudioStreamPlayer::get_pitch_scale() const { void AudioStreamPlayer::play(float p_from_pos) { if (stream_playback.is_valid()) { //mix_volume_db = volume_db; do not reset volume ramp here, can cause clicks - setseek = p_from_pos; - stop_has_priority = false; - active = true; + setseek.set(p_from_pos); + stop_has_priority.clear(); + active.set(); set_process_internal(true); } } void AudioStreamPlayer::seek(float p_seconds) { if (stream_playback.is_valid()) { - setseek = p_seconds; + setseek.set(p_seconds); } } void AudioStreamPlayer::stop() { - if (stream_playback.is_valid() && active) { - setstop = true; - stop_has_priority = true; + if (stream_playback.is_valid() && active.is_set()) { + setstop.set(); + stop_has_priority.set(); } } bool AudioStreamPlayer::is_playing() const { if (stream_playback.is_valid()) { - return active && !setstop; //&& stream_playback->is_playing(); + return active.is_set() && !setstop.is_set(); //&& stream_playback->is_playing(); } return false; @@ -267,6 +267,10 @@ bool AudioStreamPlayer::is_playing() const { float AudioStreamPlayer::get_playback_position() { if (stream_playback.is_valid()) { + float ss = setseek.get(); + if (ss >= 0.0) { + return ss; + } return stream_playback->get_playback_position(); } @@ -314,7 +318,7 @@ void AudioStreamPlayer::_set_playing(bool p_enable) { } bool AudioStreamPlayer::_is_active() const { - return active; + return active.is_set(); } void AudioStreamPlayer::set_stream_paused(bool p_pause) { @@ -344,7 +348,7 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &property) const { } void AudioStreamPlayer::_bus_layout_changed() { - _change_notify(); + notify_property_list_changed(); } Ref<AudioStreamPlayback> AudioStreamPlayer::get_stream_playback() { @@ -402,18 +406,7 @@ void AudioStreamPlayer::_bind_methods() { } AudioStreamPlayer::AudioStreamPlayer() { - mix_volume_db = 0; - pitch_scale = 1.0; - volume_db = 0; - autoplay = false; - setseek = -1; - active = false; - stream_paused = false; - stream_paused_fade = false; - mix_target = MIX_TARGET_STEREO; fadeout_buffer.resize(512); - setstop = false; - use_fadeout = false; AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer::_bus_layout_changed)); } diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h index 2d9c4cb481..aa8d088be5 100644 --- a/scene/audio/audio_stream_player.h +++ b/scene/audio/audio_stream_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,6 +31,7 @@ #ifndef AUDIO_STREAM_PLAYER_H #define AUDIO_STREAM_PLAYER_H +#include "core/templates/safe_refcount.h" #include "scene/main/node.h" #include "servers/audio/audio_stream.h" @@ -49,22 +50,22 @@ private: Ref<AudioStream> stream; Vector<AudioFrame> mix_buffer; Vector<AudioFrame> fadeout_buffer; - bool use_fadeout; - - volatile float setseek; - volatile bool active; - volatile bool setstop; - volatile bool stop_has_priority; - - float mix_volume_db; - float pitch_scale; - float volume_db; - bool autoplay; - bool stream_paused; - bool stream_paused_fade; + bool use_fadeout = false; + + SafeNumeric<float> setseek{ -1.0 }; + SafeFlag active; + SafeFlag setstop; + SafeFlag stop_has_priority; + + float mix_volume_db = 0.0; + float pitch_scale = 1.0; + float volume_db = 0.0; + bool autoplay = false; + bool stream_paused = false; + bool stream_paused_fade = false; StringName bus; - MixTarget mix_target; + MixTarget mix_target = MIX_TARGET_STEREO; void _mix_internal(bool p_fadeout); void _mix_audio(); diff --git a/scene/debugger/scene_debugger.cpp b/scene/debugger/scene_debugger.cpp index f848fc3e68..a1d4adcd41 100644 --- a/scene/debugger/scene_debugger.cpp +++ b/scene/debugger/scene_debugger.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -487,7 +487,7 @@ void LiveEditor::_send_tree() { } Array arr; - // Encoded as a flat list depth fist. + // Encoded as a flat list depth first. SceneDebuggerTree tree(scene_tree->root); tree.serialize(arr); EngineDebugger::get_singleton()->send_message("scene:scene_tree", arr); diff --git a/scene/debugger/scene_debugger.h b/scene/debugger/scene_debugger.h index af2d8904b5..9d54556187 100644 --- a/scene/debugger/scene_debugger.h +++ b/scene/debugger/scene_debugger.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -77,7 +77,7 @@ public: class SceneDebuggerTree { public: struct RemoteNode { - int child_count; + int child_count = 0; String name; String type_name; ObjectID id; diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp index 672102bf7a..c7f6c0e2da 100644 --- a/scene/gui/aspect_ratio_container.cpp +++ b/scene/gui/aspect_ratio_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/aspect_ratio_container.h b/scene/gui/aspect_ratio_container.h index 8ffc4363c3..c95c6a7274 100644 --- a/scene/gui/aspect_ratio_container.h +++ b/scene/gui/aspect_ratio_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index dadb1bea31..db13b9b11f 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -199,7 +199,6 @@ void BaseButton::set_disabled(bool p_disabled) { status.pressing_inside = false; } update(); - _change_notify("disabled"); } bool BaseButton::is_disabled() const { @@ -213,7 +212,6 @@ void BaseButton::set_pressed(bool p_pressed) { if (status.pressed == p_pressed) { return; } - _change_notify("pressed"); status.pressed = p_pressed; if (p_pressed) { @@ -448,18 +446,7 @@ void BaseButton::_bind_methods() { } BaseButton::BaseButton() { - toggle_mode = false; - shortcut_in_tooltip = true; - keep_pressed_outside = false; - status.pressed = false; - status.press_attempt = false; - status.hovering = false; - status.pressing_inside = false; - status.disabled = false; set_focus_mode(FOCUS_ALL); - action_mode = ACTION_MODE_BUTTON_RELEASE; - button_mask = BUTTON_MASK_LEFT; - shortcut_context = ObjectID(); } BaseButton::~BaseButton() { diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index 661801216d..6c7a8f3433 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -45,21 +45,21 @@ public: }; private: - int button_mask; - bool toggle_mode; - bool shortcut_in_tooltip; - bool keep_pressed_outside; + int button_mask = MOUSE_BUTTON_MASK_LEFT; + bool toggle_mode = false; + bool shortcut_in_tooltip = true; + bool keep_pressed_outside = false; Ref<Shortcut> shortcut; ObjectID shortcut_context; - ActionMode action_mode; + ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE; struct Status { - bool pressed; - bool hovering; - bool press_attempt; - bool pressing_inside; + bool pressed = false; + bool hovering = false; + bool press_attempt = false; + bool pressing_inside = false; - bool disabled; + bool disabled = false; } status; diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index fdd88d155f..7407ad5b8f 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,9 +33,9 @@ #include "margin_container.h" struct _MinSizeCache { - int min_size; - bool will_stretch; - int final_size; + int min_size = 0; + bool will_stretch = false; + int final_size = 0; }; void BoxContainer::_resort() { @@ -50,7 +50,7 @@ void BoxContainer::_resort() { int children_count = 0; int stretch_min = 0; int stretch_avail = 0; - float stretch_ratio_total = 0; + float stretch_ratio_total = 0.0; Map<Control *, _MinSizeCache> min_size_cache; for (int i = 0; i < get_child_count(); i++) { @@ -105,7 +105,7 @@ void BoxContainer::_resort() { has_stretched = true; bool refit_successful = true; //assume refit-test will go well - float error = 0; // Keep track of accumulated error in pixels + float error = 0.0; // Keep track of accumulated error in pixels for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); @@ -313,7 +313,7 @@ BoxContainer::AlignMode BoxContainer::get_alignment() const { return align; } -void BoxContainer::add_spacer(bool p_begin) { +Control *BoxContainer::add_spacer(bool p_begin) { Control *c = memnew(Control); c->set_mouse_filter(MOUSE_FILTER_PASS); //allow spacer to pass mouse events @@ -327,11 +327,12 @@ void BoxContainer::add_spacer(bool p_begin) { if (p_begin) { move_child(c, 0); } + + return c; } BoxContainer::BoxContainer(bool p_vertical) { vertical = p_vertical; - align = ALIGN_BEGIN; } void BoxContainer::_bind_methods() { diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index c4d75c3cf1..23feea565c 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,8 +44,8 @@ public: }; private: - bool vertical; - AlignMode align; + bool vertical = false; + AlignMode align = ALIGN_BEGIN; void _resort(); @@ -55,7 +55,7 @@ protected: static void _bind_methods(); public: - void add_spacer(bool p_begin = false); + Control *add_spacer(bool p_begin = false); void set_alignment(AlignMode p_align); AlignMode get_alignment() const; diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 711e5f9262..b0bcde8865 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -56,11 +56,16 @@ Size2 Button::get_minimum_size() const { } } + Ref<Font> font = get_theme_font("font"); + float font_height = font->get_height(get_theme_font_size("font_size")); + + minsize.height = MAX(font_height, minsize.height); + return get_theme_stylebox("normal")->get_minimum_size() + minsize; } -void Button::_set_internal_margin(Margin p_margin, float p_value) { - _internal_margin[p_margin] = p_value; +void Button::_set_internal_margin(Side p_side, float p_value) { + _internal_margin[p_side] = p_value; } void Button::_notification(int p_what) { @@ -102,8 +107,8 @@ void Button::_notification(int p_what) { style->draw(ci, Rect2(Point2(0, 0), size)); } color = get_theme_color("font_color"); - if (has_theme_color("icon_color_normal")) { - color_icon = get_theme_color("icon_color_normal"); + if (has_theme_color("icon_normal_color")) { + color_icon = get_theme_color("icon_normal_color"); } } break; case DRAW_HOVER_PRESSED: { @@ -117,13 +122,13 @@ void Button::_notification(int p_what) { if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - if (has_theme_color("font_color_hover_pressed")) { - color = get_theme_color("font_color_hover_pressed"); + if (has_theme_color("font_hover_pressed_color")) { + color = get_theme_color("font_hover_pressed_color"); } else { color = get_theme_color("font_color"); } - if (has_theme_color("icon_color_hover_pressed")) { - color_icon = get_theme_color("icon_color_hover_pressed"); + if (has_theme_color("icon_hover_pressed_color")) { + color_icon = get_theme_color("icon_hover_pressed_color"); } break; @@ -140,13 +145,13 @@ void Button::_notification(int p_what) { if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - if (has_theme_color("font_color_pressed")) { - color = get_theme_color("font_color_pressed"); + if (has_theme_color("font_pressed_color")) { + color = get_theme_color("font_pressed_color"); } else { color = get_theme_color("font_color"); } - if (has_theme_color("icon_color_pressed")) { - color_icon = get_theme_color("icon_color_pressed"); + if (has_theme_color("icon_pressed_color")) { + color_icon = get_theme_color("icon_pressed_color"); } } break; @@ -160,9 +165,9 @@ void Button::_notification(int p_what) { if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - color = get_theme_color("font_color_hover"); - if (has_theme_color("icon_color_hover")) { - color_icon = get_theme_color("icon_color_hover"); + color = get_theme_color("font_hover_color"); + if (has_theme_color("icon_hover_color")) { + color_icon = get_theme_color("icon_hover_color"); } } break; @@ -176,9 +181,9 @@ void Button::_notification(int p_what) { if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } - color = get_theme_color("font_color_disabled"); - if (has_theme_color("icon_color_disabled")) { - color_icon = get_theme_color("icon_color_disabled"); + color = get_theme_color("font_disabled_color"); + if (has_theme_color("icon_disabled_color")) { + color_icon = get_theme_color("icon_disabled_color"); } } break; @@ -203,14 +208,14 @@ void Button::_notification(int p_what) { color_icon.a = 0.4; } - float icon_ofs_region = 0; + float icon_ofs_region = 0.0; if (rtl) { - if (_internal_margin[MARGIN_RIGHT] > 0) { - icon_ofs_region = _internal_margin[MARGIN_RIGHT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_RIGHT] > 0) { + icon_ofs_region = _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation"); } } else { - if (_internal_margin[MARGIN_LEFT] > 0) { - icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_LEFT] > 0) { + icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } } @@ -229,13 +234,13 @@ void Button::_notification(int p_what) { } if (rtl) { - icon_region = Rect2(Point2(size.width - (icon_ofs_region + icon_width + style->get_margin(MARGIN_RIGHT)), style->get_margin(MARGIN_TOP) + (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); + icon_region = Rect2(Point2(size.width - (icon_ofs_region + icon_width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); } else { icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); } } else { if (rtl) { - icon_region = Rect2(Point2(size.width - (icon_ofs_region + _icon->get_size().width + style->get_margin(MARGIN_RIGHT)), style->get_margin(MARGIN_TOP) + Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); + icon_region = Rect2(Point2(size.width - (icon_ofs_region + _icon->get_size().width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); } else { icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); } @@ -248,28 +253,28 @@ void Button::_notification(int p_what) { int text_width = clip_text ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x; - if (_internal_margin[MARGIN_LEFT] > 0) { - text_clip -= _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_LEFT] > 0) { + text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } - if (_internal_margin[MARGIN_RIGHT] > 0) { - text_clip -= _internal_margin[MARGIN_RIGHT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_RIGHT] > 0) { + text_clip -= _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation"); } - Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0; + Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0; switch (align) { case ALIGN_LEFT: { if (rtl) { - if (_internal_margin[MARGIN_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - text_width - _internal_margin[MARGIN_RIGHT] - get_theme_constant("hseparation"); + if (_internal_margin[SIDE_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); } else { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - text_width; + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; } } else { - if (_internal_margin[MARGIN_LEFT] > 0) { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_LEFT] > 0) { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } else { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; } } text_ofs.y += style->get_offset().y; @@ -283,16 +288,16 @@ void Button::_notification(int p_what) { } break; case ALIGN_RIGHT: { if (rtl) { - if (_internal_margin[MARGIN_LEFT] > 0) { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_LEFT] > 0) { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } else { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; } } else { - if (_internal_margin[MARGIN_RIGHT] > 0) { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - text_width - _internal_margin[MARGIN_RIGHT] - get_theme_constant("hseparation"); + if (_internal_margin[SIDE_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); } else { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - text_width; + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; } } text_ofs.y += style->get_offset().y; @@ -303,13 +308,13 @@ void Button::_notification(int p_what) { text_ofs.x -= icon_ofs.x; } - Color font_outline_modulate = get_theme_color("font_outline_modulate"); + Color font_outline_color = get_theme_color("font_outline_color"); int outline_size = get_theme_constant("outline_size"); - if (outline_size > 0 && font_outline_modulate.a > 0) { - text_buf->draw_outline(ci, text_ofs.floor(), outline_size, font_outline_modulate); + if (outline_size > 0 && font_outline_color.a > 0) { + text_buf->draw_outline(ci, text_ofs, outline_size, font_outline_color); } - text_buf->draw(ci, text_ofs.floor(), color); + text_buf->draw(ci, text_ofs, color); if (!_icon.is_null() && icon_region.size.width > 0) { draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); @@ -338,7 +343,6 @@ void Button::set_text(const String &p_text) { _shape(); update(); - _change_notify("text"); minimum_size_changed(); } } @@ -399,7 +403,6 @@ void Button::set_icon(const Ref<Texture2D> &p_icon) { if (icon != p_icon) { icon = p_icon; update(); - _change_notify("icon"); minimum_size_changed(); } } @@ -424,7 +427,6 @@ void Button::set_flat(bool p_flat) { if (flat != p_flat) { flat = p_flat; update(); - _change_notify("flat"); } } @@ -474,7 +476,7 @@ bool Button::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } @@ -544,16 +546,8 @@ Button::Button(const String &p_text) { text_buf.instance(); text_buf->set_flags(TextServer::BREAK_MANDATORY); - flat = false; - clip_text = false; - expand_icon = false; set_mouse_filter(MOUSE_FILTER_STOP); set_text(p_text); - align = ALIGN_CENTER; - - for (int i = 0; i < 4; i++) { - _internal_margin[i] = 0; - } } Button::~Button() { diff --git a/scene/gui/button.h b/scene/gui/button.h index da89e5e6c4..d968f63f51 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -45,7 +45,7 @@ public: }; private: - bool flat; + bool flat = false; String text; String xl_text; Ref<TextParagraph> text_buf; @@ -55,15 +55,15 @@ private: TextDirection text_direction = TEXT_DIRECTION_AUTO; Ref<Texture2D> icon; - bool expand_icon; - bool clip_text; - TextAlign align; - float _internal_margin[4]; + bool expand_icon = false; + bool clip_text = false; + TextAlign align = ALIGN_CENTER; + float _internal_margin[4] = {}; void _shape(); protected: - void _set_internal_margin(Margin p_margin, float p_value); + void _set_internal_margin(Side p_side, float p_value); void _notification(int p_what); static void _bind_methods(); diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index 1a72f3ca4d..909516e7ef 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -95,6 +95,4 @@ void CenterContainer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_top_left"), "set_use_top_left", "is_using_top_left"); } -CenterContainer::CenterContainer() { - use_top_left = false; -} +CenterContainer::CenterContainer() {} diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h index 638843c389..0944f200fc 100644 --- a/scene/gui/center_container.h +++ b/scene/gui/center_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class CenterContainer : public Container { GDCLASS(CenterContainer, Container); - bool use_top_left; + bool use_top_left = false; protected: void _notification(int p_what); diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 0c78369688..c0650a8f3f 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,7 +34,9 @@ Size2 CheckBox::get_icon_size() const { Ref<Texture2D> checked = Control::get_theme_icon("checked"); + Ref<Texture2D> checked_disabled = Control::get_theme_icon("checked_disabled"); Ref<Texture2D> unchecked = Control::get_theme_icon("unchecked"); + Ref<Texture2D> unchecked_disabled = Control::get_theme_icon("unchecked_disabled"); Ref<Texture2D> radio_checked = Control::get_theme_icon("radio_checked"); Ref<Texture2D> radio_unchecked = Control::get_theme_icon("radio_unchecked"); @@ -62,7 +64,7 @@ Size2 CheckBox::get_minimum_size() const { minsize.width += get_theme_constant("hseparation"); } Ref<StyleBox> sb = get_theme_stylebox("normal"); - minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); + minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); return minsize; } @@ -70,24 +72,24 @@ Size2 CheckBox::get_minimum_size() const { void CheckBox::_notification(int p_what) { if ((p_what == NOTIFICATION_THEME_CHANGED) || (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || (p_what == NOTIFICATION_TRANSLATION_CHANGED))) { if (is_layout_rtl()) { - _set_internal_margin(MARGIN_LEFT, 0.f); - _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); + _set_internal_margin(SIDE_LEFT, 0.f); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); } else { - _set_internal_margin(MARGIN_LEFT, get_icon_size().width); - _set_internal_margin(MARGIN_RIGHT, 0.f); + _set_internal_margin(SIDE_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, 0.f); } } else if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); - Ref<Texture2D> on = Control::get_theme_icon(is_radio() ? "radio_checked" : "checked"); - Ref<Texture2D> off = Control::get_theme_icon(is_radio() ? "radio_unchecked" : "unchecked"); + Ref<Texture2D> on = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_checked" : "checked", is_disabled() ? "_disabled" : "")); + Ref<Texture2D> off = Control::get_theme_icon(vformat("%s%s", is_radio() ? "radio_unchecked" : "unchecked", is_disabled() ? "_disabled" : "")); Ref<StyleBox> sb = get_theme_stylebox("normal"); Vector2 ofs; if (is_layout_rtl()) { - ofs.x = get_size().x - sb->get_margin(MARGIN_RIGHT) - get_icon_size().width; + ofs.x = get_size().x - sb->get_margin(SIDE_RIGHT) - get_icon_size().width; } else { - ofs.x = sb->get_margin(MARGIN_LEFT); + ofs.x = sb->get_margin(SIDE_LEFT); } ofs.y = int((get_size().height - get_icon_size().height) / 2) + get_theme_constant("check_vadjust"); @@ -110,9 +112,9 @@ CheckBox::CheckBox(const String &p_text) : set_text_align(ALIGN_LEFT); if (is_layout_rtl()) { - _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); } else { - _set_internal_margin(MARGIN_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_LEFT, get_icon_size().width); } } diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h index cc00524698..9fb0aea218 100644 --- a/scene/gui/check_box.h +++ b/scene/gui/check_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index e58f56a99b..a8bf449355 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -55,7 +55,7 @@ Size2 CheckButton::get_minimum_size() const { minsize.width += get_theme_constant("hseparation"); } Ref<StyleBox> sb = get_theme_stylebox("normal"); - minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(MARGIN_TOP) + sb->get_margin(MARGIN_BOTTOM)); + minsize.height = MAX(minsize.height, tex_size.height + sb->get_margin(SIDE_TOP) + sb->get_margin(SIDE_BOTTOM)); return minsize; } @@ -63,11 +63,11 @@ Size2 CheckButton::get_minimum_size() const { void CheckButton::_notification(int p_what) { if ((p_what == NOTIFICATION_THEME_CHANGED) || (p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED) || (p_what == NOTIFICATION_TRANSLATION_CHANGED)) { if (is_layout_rtl()) { - _set_internal_margin(MARGIN_LEFT, get_icon_size().width); - _set_internal_margin(MARGIN_RIGHT, 0.f); + _set_internal_margin(SIDE_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, 0.f); } else { - _set_internal_margin(MARGIN_LEFT, 0.f); - _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); + _set_internal_margin(SIDE_LEFT, 0.f); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); } } else if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); @@ -91,9 +91,9 @@ void CheckButton::_notification(int p_what) { Size2 tex_size = get_icon_size(); if (rtl) { - ofs.x = sb->get_margin(MARGIN_LEFT); + ofs.x = sb->get_margin(SIDE_LEFT); } else { - ofs.x = get_size().width - (tex_size.width + sb->get_margin(MARGIN_RIGHT)); + ofs.x = get_size().width - (tex_size.width + sb->get_margin(SIDE_RIGHT)); } ofs.y = (get_size().height - tex_size.height) / 2 + get_theme_constant("check_vadjust"); @@ -109,9 +109,9 @@ CheckButton::CheckButton() { set_toggle_mode(true); set_text_align(ALIGN_LEFT); if (is_layout_rtl()) { - _set_internal_margin(MARGIN_LEFT, get_icon_size().width); + _set_internal_margin(SIDE_LEFT, get_icon_size().width); } else { - _set_internal_margin(MARGIN_RIGHT, get_icon_size().width); + _set_internal_margin(SIDE_RIGHT, get_icon_size().width); } } diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h index 99a12a3270..29c557ce89 100644 --- a/scene/gui/check_button.h +++ b/scene/gui/check_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 59cfbccf99..28a0ea0100 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h index c989e5ed79..d0c39ec0f1 100644 --- a/scene/gui/code_edit.h +++ b/scene/gui/code_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index 6ebd1011e9..a919ae8dd0 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,6 +52,7 @@ void ColorPicker::_notification(int p_what) { btn_pick->set_icon(get_theme_icon("screen_picker", "ColorPicker")); bt_add_preset->set_icon(get_theme_icon("add_preset")); + _update_controls(); _update_color(); #ifdef TOOLS_ENABLED @@ -66,7 +67,7 @@ void ColorPicker::_notification(int p_what) { } break; case NOTIFICATION_PARENTED: { for (int i = 0; i < 4; i++) { - set_margin((Margin)i, get_margin((Margin)i) + get_theme_constant("margin")); + set_offset((Side)i, get_offset((Side)i) + get_theme_constant("margin")); } } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -112,6 +113,24 @@ void ColorPicker::_update_controls() { btn_hsv->set_disabled(false); } + if (raw_mode_enabled) { + for (int i = 0; i < 3; i++) { + scroll[i]->add_theme_icon_override("grabber", Ref<Texture2D>()); + scroll[i]->add_theme_icon_override("grabber_highlight", Ref<Texture2D>()); + scroll[i]->add_theme_style_override("slider", Ref<StyleBox>()); + scroll[i]->add_theme_style_override("grabber_area", Ref<StyleBox>()); + scroll[i]->add_theme_style_override("grabber_area_highlight", Ref<StyleBox>()); + } + } else { + for (int i = 0; i < 3; i++) { + scroll[i]->add_theme_icon_override("grabber", get_theme_icon("bar_arrow")); + scroll[i]->add_theme_icon_override("grabber_highlight", get_theme_icon("bar_arrow")); + scroll[i]->add_theme_style_override("slider", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); + scroll[i]->add_theme_style_override("grabber_area", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); + scroll[i]->add_theme_style_override("grabber_area_highlight", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); + } + } + if (edit_alpha) { values[3]->show(); scroll[3]->show(); @@ -165,10 +184,13 @@ void ColorPicker::_value_changed(double) { } if (hsv_mode_enabled) { - color.set_hsv(scroll[0]->get_value() / 360.0, - scroll[1]->get_value() / 100.0, - scroll[2]->get_value() / 100.0, - scroll[3]->get_value() / 255.0); + h = scroll[0]->get_value() / 360.0; + s = scroll[1]->get_value() / 100.0; + v = scroll[2]->get_value() / 100.0; + color.set_hsv(h, s, v, scroll[3]->get_value() / 255.0); + + last_hsv = color; + } else { for (int i = 0; i < 4; i++) { color.components[i] = scroll[i]->get_value() / (raw_mode_enabled ? 1.0 : 255.0); @@ -239,6 +261,9 @@ void ColorPicker::_update_color(bool p_update_sliders) { sample->update(); uv_edit->update(); w_edit->update(); + for (int i = 0; i < 4; i++) { + scroll[i]->update(); + } updating = false; } @@ -452,11 +477,74 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) { } } +void ColorPicker::_slider_draw(int p_which) { + Vector<Vector2> pos; + pos.resize(4); + Vector<Color> col; + col.resize(4); + Size2 size = scroll[p_which]->get_size(); + Color left_color; + Color right_color; +#ifdef TOOLS_ENABLED + const real_t margin = 4 * EDSCALE; +#else + const real_t margin = 4; +#endif + + if (p_which == 3) { + scroll[p_which]->draw_texture_rect(get_theme_icon("preset_bg", "ColorPicker"), Rect2(Point2(0, margin), Size2(size.x, margin)), true); + + left_color = color; + left_color.a = 0; + right_color = color; + right_color.a = 1; + } else { + if (raw_mode_enabled) { + return; + } + if (hsv_mode_enabled) { + if (p_which == 0) { + Ref<Texture2D> hue = get_theme_icon("color_hue", "ColorPicker"); + scroll[p_which]->draw_set_transform(Point2(), -Math_PI / 2, Size2(1.0, 1.0)); + scroll[p_which]->draw_texture_rect(hue, Rect2(Vector2(margin * -2, 0), Vector2(scroll[p_which]->get_size().x, margin)), false, Color(1, 1, 1), true); + return; + } + Color s_col; + Color v_col; + s_col.set_hsv(h, 0, v); + left_color = (p_which == 1) ? s_col : Color(0, 0, 0); + s_col.set_hsv(h, 1, v); + v_col.set_hsv(h, s, 1); + right_color = (p_which == 1) ? s_col : v_col; + } else { + left_color = Color( + p_which == 0 ? 0 : color.r, + p_which == 1 ? 0 : color.g, + p_which == 2 ? 0 : color.b); + right_color = Color( + p_which == 0 ? 1 : color.r, + p_which == 1 ? 1 : color.g, + p_which == 2 ? 1 : color.b); + } + } + + col.set(0, left_color); + col.set(1, right_color); + col.set(2, right_color); + col.set(3, left_color); + pos.set(0, Vector2(0, margin)); + pos.set(1, Vector2(size.x, margin)); + pos.set(2, Vector2(size.x, margin * 2)); + pos.set(3, Vector2(0, margin * 2)); + + scroll[p_which]->draw_polygon(pos, col); +} + void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; if (bev.is_valid()) { - if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { + if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { changing_color = true; float x = CLAMP((float)bev->get_position().x, 0, uv_edit->get_size().width); float y = CLAMP((float)bev->get_position().y, 0, uv_edit->get_size().height); @@ -469,7 +557,7 @@ void ColorPicker::_uv_input(const Ref<InputEvent> &p_event) { if (!deferred_mode_enabled) { emit_signal("color_changed", color); } - } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { + } else if (deferred_mode_enabled && !bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { emit_signal("color_changed", color); changing_color = false; } else { @@ -501,7 +589,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> bev = p_event; if (bev.is_valid()) { - if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { + if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { changing_color = true; float y = CLAMP((float)bev->get_position().y, 0, w_edit->get_size().height); h = y / w_edit->get_size().height; @@ -514,7 +602,7 @@ void ColorPicker::_w_input(const Ref<InputEvent> &p_event) { _update_color(); if (!deferred_mode_enabled) { emit_signal("color_changed", color); - } else if (!bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { + } else if (!bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { emit_signal("color_changed", color); } } @@ -542,7 +630,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { if (bev.is_valid()) { int index = 0; - if (bev->is_pressed() && bev->get_button_index() == BUTTON_LEFT) { + if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_LEFT) { for (int i = 0; i < presets.size(); i++) { int x = (i % presets_per_row) * bt_add_preset->get_size().x; int y = (Math::floor((float)i / presets_per_row)) * bt_add_preset->get_size().y; @@ -553,7 +641,7 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { set_pick_color(presets[index]); _update_color(); emit_signal("color_changed", color); - } else if (bev->is_pressed() && bev->get_button_index() == BUTTON_RIGHT && presets_enabled) { + } else if (bev->is_pressed() && bev->get_button_index() == MOUSE_BUTTON_RIGHT && presets_enabled) { index = bev->get_position().x / (preset->get_size().x / presets.size()); Color clicked_preset = presets[index]; erase_preset(clicked_preset); @@ -577,8 +665,12 @@ void ColorPicker::_preset_input(const Ref<InputEvent> &p_event) { } void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { + if (!is_inside_tree()) { + return; + } + Ref<InputEventMouseButton> bev = p_event; - if (bev.is_valid() && bev->get_button_index() == BUTTON_LEFT && !bev->is_pressed()) { + if (bev.is_valid() && bev->get_button_index() == MOUSE_BUTTON_LEFT && !bev->is_pressed()) { emit_signal("color_changed", color); screen->hide(); } @@ -590,8 +682,8 @@ void ColorPicker::_screen_input(const Ref<InputEvent> &p_event) { return; } - Ref<Image> img = r->get_texture()->get_data(); - if (img.is_valid() && !img->empty()) { + Ref<Image> img = r->get_texture()->get_image(); + if (img.is_valid() && !img->is_empty()) { Vector2 ofs = mev->get_global_position() - r->get_visible_rect().get_position(); Color c = img->get_pixel(ofs.x, r->get_visible_rect().size.height - ofs.y); @@ -606,12 +698,16 @@ void ColorPicker::_add_preset_pressed() { } void ColorPicker::_screen_pick_pressed() { + if (!is_inside_tree()) { + return; + } + Viewport *r = get_tree()->get_root(); if (!screen) { screen = memnew(Control); r->add_child(screen); screen->set_as_top_level(true); - screen->set_anchors_and_margins_preset(Control::PRESET_WIDE); + screen->set_anchors_and_offsets_preset(Control::PRESET_WIDE); screen->set_default_cursor_shape(CURSOR_POINTING_HAND); screen->connect("gui_input", callable_mp(this, &ColorPicker::_screen_input)); // It immediately toggles off in the first press otherwise. @@ -718,17 +814,6 @@ void ColorPicker::_bind_methods() { ColorPicker::ColorPicker() : BoxContainer(true) { - updating = true; - edit_alpha = true; - text_is_constructor = false; - hsv_mode_enabled = false; - raw_mode_enabled = false; - deferred_mode_enabled = false; - changing_color = false; - presets_enabled = true; - presets_visible = true; - screen = nullptr; - HBoxContainer *hb_edit = memnew(HBoxContainer); add_child(hb_edit); hb_edit->set_v_size_flags(SIZE_EXPAND_FILL); @@ -798,10 +883,16 @@ ColorPicker::ColorPicker() : scroll[i]->set_h_size_flags(SIZE_EXPAND_FILL); scroll[i]->connect("value_changed", callable_mp(this, &ColorPicker::_value_changed)); + scroll[i]->connect("draw", callable_mp(this, &ColorPicker::_slider_draw), make_binds(i)); vbr->add_child(hbc); } labels[3]->set_text("A"); + scroll[3]->add_theme_icon_override("grabber", get_theme_icon("bar_arrow")); + scroll[3]->add_theme_icon_override("grabber_highlight", get_theme_icon("bar_arrow")); + scroll[3]->add_theme_style_override("slider", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); + scroll[3]->add_theme_style_override("grabber_area", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); + scroll[3]->add_theme_style_override("grabber_area_highlight", Ref<StyleBoxEmpty>(memnew(StyleBoxEmpty))); HBoxContainer *hhb = memnew(HBoxContainer); vbr->add_child(hhb); @@ -973,7 +1064,7 @@ void ColorPickerButton::_update_picker() { popup = memnew(PopupPanel); popup->set_wrap_controls(true); picker = memnew(ColorPicker); - picker->set_anchors_and_margins_preset(PRESET_WIDE); + picker->set_anchors_and_offsets_preset(PRESET_WIDE); popup->add_child(picker); add_child(popup); picker->connect("color_changed", callable_mp(this, &ColorPickerButton::_color_changed)); @@ -1001,12 +1092,5 @@ void ColorPickerButton::_bind_methods() { } ColorPickerButton::ColorPickerButton() { - // Initialization is now done deferred, - // this improves performance in the inspector as the color picker - // can be expensive to initialize. - picker = nullptr; - popup = nullptr; - edit_alpha = true; - set_toggle_mode(true); } diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 128664b49d..24e1746c41 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,7 +46,7 @@ class ColorPicker : public BoxContainer { GDCLASS(ColorPicker, BoxContainer); private: - Control *screen; + Control *screen = nullptr; Control *uv_edit; Control *w_edit; TextureRect *sample; @@ -64,20 +64,22 @@ private: Label *labels[4]; Button *text_type; LineEdit *c_text; - bool edit_alpha; + bool edit_alpha = true; Size2i ms; - bool text_is_constructor; - int presets_per_row; + bool text_is_constructor = false; + int presets_per_row = 0; Color color; - bool raw_mode_enabled; - bool hsv_mode_enabled; - bool deferred_mode_enabled; - bool updating; - bool changing_color; - bool presets_enabled; - bool presets_visible; - float h, s, v; + bool raw_mode_enabled = false; + bool hsv_mode_enabled = false; + bool deferred_mode_enabled = false; + bool updating = true; + bool changing_color = false; + bool presets_enabled = true; + bool presets_visible = true; + float h = 0.0; + float s = 0.0; + float v = 0.0; Color last_hsv; void _html_entered(const String &p_html); @@ -89,6 +91,7 @@ private: void _text_type_toggled(); void _sample_draw(); void _hsv_draw(int p_which, Control *c); + void _slider_draw(int p_which); void _uv_input(const Ref<InputEvent> &p_event); void _w_input(const Ref<InputEvent> &p_event); @@ -139,10 +142,14 @@ public: class ColorPickerButton : public Button { GDCLASS(ColorPickerButton, Button); - PopupPanel *popup; - ColorPicker *picker; + // Initialization is now done deferred, + // this improves performance in the inspector as the color picker + // can be expensive to initialize. + + PopupPanel *popup = nullptr; + ColorPicker *picker = nullptr; Color color; - bool edit_alpha; + bool edit_alpha = true; void _color_changed(const Color &p_color); void _modal_closed(); diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp index 0c38b93c60..e35d37d520 100644 --- a/scene/gui/color_rect.cpp +++ b/scene/gui/color_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/color_rect.h b/scene/gui/color_rect.h index 61d57f7cca..5c650f9f01 100644 --- a/scene/gui/color_rect.h +++ b/scene/gui/color_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index f01da703c1..2e6b798eea 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -163,7 +163,7 @@ String Container::get_configuration_warning() const { String warning = Control::get_configuration_warning(); if (get_class() == "Container" && get_script().is_null()) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -180,7 +180,6 @@ void Container::_bind_methods() { } Container::Container() { - pending_sort = false; // All containers should let mouse events pass by default. set_mouse_filter(MOUSE_FILTER_PASS); } diff --git a/scene/gui/container.h b/scene/gui/container.h index b789bcf3b0..a4f392a3ae 100644 --- a/scene/gui/container.h +++ b/scene/gui/container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class Container : public Control { GDCLASS(Container, Control); - bool pending_sort; + bool pending_sort = false; void _sort_children(); void _child_minsize_changed(); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index bc37045386..1e13597e94 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -58,42 +58,46 @@ Dictionary Control::_edit_get_state() const { s["scale"] = get_scale(); s["pivot"] = get_pivot_offset(); Array anchors; - anchors.push_back(get_anchor(MARGIN_LEFT)); - anchors.push_back(get_anchor(MARGIN_TOP)); - anchors.push_back(get_anchor(MARGIN_RIGHT)); - anchors.push_back(get_anchor(MARGIN_BOTTOM)); + anchors.push_back(get_anchor(SIDE_LEFT)); + anchors.push_back(get_anchor(SIDE_TOP)); + anchors.push_back(get_anchor(SIDE_RIGHT)); + anchors.push_back(get_anchor(SIDE_BOTTOM)); s["anchors"] = anchors; - Array margins; - margins.push_back(get_margin(MARGIN_LEFT)); - margins.push_back(get_margin(MARGIN_TOP)); - margins.push_back(get_margin(MARGIN_RIGHT)); - margins.push_back(get_margin(MARGIN_BOTTOM)); - s["margins"] = margins; + Array offsets; + offsets.push_back(get_offset(SIDE_LEFT)); + offsets.push_back(get_offset(SIDE_TOP)); + offsets.push_back(get_offset(SIDE_RIGHT)); + offsets.push_back(get_offset(SIDE_BOTTOM)); + s["offsets"] = offsets; return s; } void Control::_edit_set_state(const Dictionary &p_state) { + ERR_FAIL_COND((p_state.size() <= 0) || + !p_state.has("rotation") || !p_state.has("scale") || + !p_state.has("pivot") || !p_state.has("anchors") || !p_state.has("offsets")); Dictionary state = p_state; set_rotation(state["rotation"]); set_scale(state["scale"]); set_pivot_offset(state["pivot"]); Array anchors = state["anchors"]; - data.anchor[MARGIN_LEFT] = anchors[0]; - data.anchor[MARGIN_TOP] = anchors[1]; - data.anchor[MARGIN_RIGHT] = anchors[2]; - data.anchor[MARGIN_BOTTOM] = anchors[3]; - Array margins = state["margins"]; - data.margin[MARGIN_LEFT] = margins[0]; - data.margin[MARGIN_TOP] = margins[1]; - data.margin[MARGIN_RIGHT] = margins[2]; - data.margin[MARGIN_BOTTOM] = margins[3]; + data.anchor[SIDE_LEFT] = anchors[0]; + data.anchor[SIDE_TOP] = anchors[1]; + data.anchor[SIDE_RIGHT] = anchors[2]; + data.anchor[SIDE_BOTTOM] = anchors[3]; + Array offsets = state["offsets"]; + data.offset[SIDE_LEFT] = offsets[0]; + data.offset[SIDE_TOP] = offsets[1]; + data.offset[SIDE_RIGHT] = offsets[2]; + data.offset[SIDE_BOTTOM] = offsets[3]; _size_changed(); } void Control::_edit_set_position(const Point2 &p_position) { #ifdef TOOLS_ENABLED - set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); + ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins."); + set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled() && Object::cast_to<Control>(data.parent)); #else // Unlikely to happen. TODO: enclose all _edit_ functions into TOOLS_ENABLED set_position(p_position); @@ -114,6 +118,7 @@ Size2 Control::_edit_get_scale() const { void Control::_edit_set_rect(const Rect2 &p_edit_rect) { #ifdef TOOLS_ENABLED + ERR_FAIL_COND_MSG(!Engine::get_singleton()->is_editor_hint(), "This function can only be used from editor plugins."); set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); set_size(p_edit_rect.size.snapped(Vector2(1, 1)), CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); #else @@ -131,11 +136,11 @@ bool Control::_edit_use_rect() const { return true; } -void Control::_edit_set_rotation(float p_rotation) { +void Control::_edit_set_rotation(real_t p_rotation) { set_rotation(p_rotation); } -float Control::_edit_get_rotation() const { +real_t Control::_edit_get_rotation() const { return get_rotation(); } @@ -285,15 +290,11 @@ void Control::_update_minimum_size() { } Size2 minsize = get_combined_minimum_size(); - if (minsize.x > data.size_cache.x || - minsize.y > data.size_cache.y) { - _size_changed(); - } - data.updating_last_minimum_size = false; if (minsize != data.last_minimum_size) { data.last_minimum_size = minsize; + _size_changed(); emit_signal(SceneStringNames::get_singleton()->minimum_size_changed); } } @@ -439,14 +440,14 @@ bool Control::is_layout_rtl() const { } else if (parent_window) { return parent_window->is_layout_rtl(); } else { - if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) { + if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(locale); } } else if (data.layout_dir == LAYOUT_DIRECTION_LOCALE) { - if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) { + if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); @@ -456,6 +457,10 @@ bool Control::is_layout_rtl() const { } } +void Control::_clear_size_warning() { + data.size_warning = false; +} + //moved theme configuration here, so controls can set up even if still not inside active scene void Control::add_child_notify(Node *p_child) { @@ -503,7 +508,9 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_EXIT_TREE: { get_viewport()->_gui_remove_control(this); - + } break; + case NOTIFICATION_READY: { + connect("ready", callable_mp(this, &Control::_clear_size_warning), varray(), CONNECT_DEFERRED | CONNECT_ONESHOT); } break; case NOTIFICATION_ENTER_CANVAS: { @@ -575,7 +582,7 @@ void Control::_notification(int p_notification) { } break; case NOTIFICATION_MOVED_IN_PARENT: { - // some parents need to know the order of the childrens to draw (like TabContainer) + // some parents need to know the order of the children to draw (like TabContainer) // update if necessary if (data.parent) { data.parent->update(); @@ -709,7 +716,7 @@ bool Control::can_drop_data(const Point2 &p_point, const Variant &p_data) const } } - return Variant(); + return false; } void Control::drop_data(const Point2 &p_point, const Variant &p_data) { @@ -1227,15 +1234,15 @@ Size2 Control::get_parent_area_size() const { void Control::_size_changed() { Rect2 parent_rect = get_parent_anchorable_rect(); - float margin_pos[4]; + real_t edge_pos[4]; for (int i = 0; i < 4; i++) { - float area = parent_rect.size[i & 1]; - margin_pos[i] = data.margin[i] + (data.anchor[i] * area); + real_t area = parent_rect.size[i & 1]; + edge_pos[i] = data.offset[i] + (data.anchor[i] * area); } - Point2 new_pos_cache = Point2(margin_pos[0], margin_pos[1]); - Size2 new_size_cache = Point2(margin_pos[2], margin_pos[3]) - new_pos_cache; + Point2 new_pos_cache = Point2(edge_pos[0], edge_pos[1]); + Size2 new_size_cache = Point2(edge_pos[2], edge_pos[3]) - new_pos_cache; Size2 minimum_size = get_combined_minimum_size(); @@ -1275,7 +1282,6 @@ void Control::_size_changed() { } if (pos_changed || size_changed) { item_rect_changed(size_changed); - _change_notify_margins(); _notify_transform(); } @@ -1285,29 +1291,29 @@ void Control::_size_changed() { } } -void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) { - ERR_FAIL_INDEX((int)p_margin, 4); +void Control::set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset, bool p_push_opposite_anchor) { + ERR_FAIL_INDEX((int)p_side, 4); Rect2 parent_rect = get_parent_anchorable_rect(); - float parent_range = (p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? parent_rect.size.x : parent_rect.size.y; - float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range; - float previous_opposite_margin_pos = data.margin[(p_margin + 2) % 4] + data.anchor[(p_margin + 2) % 4] * parent_range; + real_t parent_range = (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) ? parent_rect.size.x : parent_rect.size.y; + real_t previous_pos = data.offset[p_side] + data.anchor[p_side] * parent_range; + real_t previous_opposite_pos = data.offset[(p_side + 2) % 4] + data.anchor[(p_side + 2) % 4] * parent_range; - data.anchor[p_margin] = p_anchor; + data.anchor[p_side] = p_anchor; - if (((p_margin == MARGIN_LEFT || p_margin == MARGIN_TOP) && data.anchor[p_margin] > data.anchor[(p_margin + 2) % 4]) || - ((p_margin == MARGIN_RIGHT || p_margin == MARGIN_BOTTOM) && data.anchor[p_margin] < data.anchor[(p_margin + 2) % 4])) { + if (((p_side == SIDE_LEFT || p_side == SIDE_TOP) && data.anchor[p_side] > data.anchor[(p_side + 2) % 4]) || + ((p_side == SIDE_RIGHT || p_side == SIDE_BOTTOM) && data.anchor[p_side] < data.anchor[(p_side + 2) % 4])) { if (p_push_opposite_anchor) { - data.anchor[(p_margin + 2) % 4] = data.anchor[p_margin]; + data.anchor[(p_side + 2) % 4] = data.anchor[p_side]; } else { - data.anchor[p_margin] = data.anchor[(p_margin + 2) % 4]; + data.anchor[p_side] = data.anchor[(p_side + 2) % 4]; } } - if (!p_keep_margin) { - data.margin[p_margin] = previous_margin_pos - data.anchor[p_margin] * parent_range; + if (!p_keep_offset) { + data.offset[p_side] = previous_pos - data.anchor[p_side] * parent_range; if (p_push_opposite_anchor) { - data.margin[(p_margin + 2) % 4] = previous_opposite_margin_pos - data.anchor[(p_margin + 2) % 4] * parent_range; + data.offset[(p_side + 2) % 4] = previous_opposite_pos - data.anchor[(p_side + 2) % 4] * parent_range; } } if (is_inside_tree()) { @@ -1315,22 +1321,18 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo } update(); - _change_notify("anchor_left"); - _change_notify("anchor_right"); - _change_notify("anchor_top"); - _change_notify("anchor_bottom"); } -void Control::_set_anchor(Margin p_margin, float p_anchor) { - set_anchor(p_margin, p_anchor); +void Control::_set_anchor(Side p_side, real_t p_anchor) { + set_anchor(p_side, p_anchor); } -void Control::set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos, bool p_push_opposite_anchor) { - set_anchor(p_margin, p_anchor, false, p_push_opposite_anchor); - set_margin(p_margin, p_pos); +void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor) { + set_anchor(p_side, p_anchor, false, p_push_opposite_anchor); + set_offset(p_side, p_pos); } -void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { +void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets) { ERR_FAIL_INDEX((int)p_preset, 16); //Left @@ -1343,21 +1345,21 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_LEFT_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_LEFT, ANCHOR_BEGIN, p_keep_margins); + set_anchor(SIDE_LEFT, ANCHOR_BEGIN, p_keep_offsets); break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - set_anchor(MARGIN_LEFT, 0.5, p_keep_margins); + set_anchor(SIDE_LEFT, 0.5, p_keep_offsets); break; case PRESET_TOP_RIGHT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_RIGHT: case PRESET_RIGHT_WIDE: - set_anchor(MARGIN_LEFT, ANCHOR_END, p_keep_margins); + set_anchor(SIDE_LEFT, ANCHOR_END, p_keep_offsets); break; } @@ -1371,21 +1373,21 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_TOP_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_TOP, ANCHOR_BEGIN, p_keep_margins); + set_anchor(SIDE_TOP, ANCHOR_BEGIN, p_keep_offsets); break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - set_anchor(MARGIN_TOP, 0.5, p_keep_margins); + set_anchor(SIDE_TOP, 0.5, p_keep_offsets); break; case PRESET_BOTTOM_LEFT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_BOTTOM: case PRESET_BOTTOM_WIDE: - set_anchor(MARGIN_TOP, ANCHOR_END, p_keep_margins); + set_anchor(SIDE_TOP, ANCHOR_END, p_keep_offsets); break; } @@ -1395,14 +1397,14 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_BOTTOM_LEFT: case PRESET_CENTER_LEFT: case PRESET_LEFT_WIDE: - set_anchor(MARGIN_RIGHT, ANCHOR_BEGIN, p_keep_margins); + set_anchor(SIDE_RIGHT, ANCHOR_BEGIN, p_keep_offsets); break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - set_anchor(MARGIN_RIGHT, 0.5, p_keep_margins); + set_anchor(SIDE_RIGHT, 0.5, p_keep_offsets); break; case PRESET_TOP_RIGHT: @@ -1413,7 +1415,7 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_BOTTOM_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_RIGHT, ANCHOR_END, p_keep_margins); + set_anchor(SIDE_RIGHT, ANCHOR_END, p_keep_offsets); break; } @@ -1423,14 +1425,14 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_TOP_RIGHT: case PRESET_CENTER_TOP: case PRESET_TOP_WIDE: - set_anchor(MARGIN_BOTTOM, ANCHOR_BEGIN, p_keep_margins); + set_anchor(SIDE_BOTTOM, ANCHOR_BEGIN, p_keep_offsets); break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - set_anchor(MARGIN_BOTTOM, 0.5, p_keep_margins); + set_anchor(SIDE_BOTTOM, 0.5, p_keep_offsets); break; case PRESET_BOTTOM_LEFT: @@ -1441,12 +1443,12 @@ void Control::set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins) { case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - set_anchor(MARGIN_BOTTOM, ANCHOR_END, p_keep_margins); + set_anchor(SIDE_BOTTOM, ANCHOR_END, p_keep_offsets); break; } } -void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { +void Control::set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { ERR_FAIL_INDEX((int)p_preset, 16); ERR_FAIL_INDEX((int)p_resize_mode, 4); @@ -1462,7 +1464,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz Rect2 parent_rect = get_parent_anchorable_rect(); - float x = parent_rect.size.x; + real_t x = parent_rect.size.x; if (is_layout_rtl()) { x = parent_rect.size.x - x - new_size.x; } @@ -1476,21 +1478,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_LEFT_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - data.margin[0] = x * (0.0 - data.anchor[0]) + p_margin + parent_rect.position.x; + data.offset[0] = x * (0.0 - data.anchor[0]) + p_margin + parent_rect.position.x; break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - data.margin[0] = x * (0.5 - data.anchor[0]) - new_size.x / 2 + parent_rect.position.x; + data.offset[0] = x * (0.5 - data.anchor[0]) - new_size.x / 2 + parent_rect.position.x; break; case PRESET_TOP_RIGHT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_RIGHT: case PRESET_RIGHT_WIDE: - data.margin[0] = x * (1.0 - data.anchor[0]) - new_size.x - p_margin + parent_rect.position.x; + data.offset[0] = x * (1.0 - data.anchor[0]) - new_size.x - p_margin + parent_rect.position.x; break; } @@ -1504,21 +1506,21 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_TOP_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - data.margin[1] = parent_rect.size.y * (0.0 - data.anchor[1]) + p_margin + parent_rect.position.y; + data.offset[1] = parent_rect.size.y * (0.0 - data.anchor[1]) + p_margin + parent_rect.position.y; break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - data.margin[1] = parent_rect.size.y * (0.5 - data.anchor[1]) - new_size.y / 2 + parent_rect.position.y; + data.offset[1] = parent_rect.size.y * (0.5 - data.anchor[1]) - new_size.y / 2 + parent_rect.position.y; break; case PRESET_BOTTOM_LEFT: case PRESET_BOTTOM_RIGHT: case PRESET_CENTER_BOTTOM: case PRESET_BOTTOM_WIDE: - data.margin[1] = parent_rect.size.y * (1.0 - data.anchor[1]) - new_size.y - p_margin + parent_rect.position.y; + data.offset[1] = parent_rect.size.y * (1.0 - data.anchor[1]) - new_size.y - p_margin + parent_rect.position.y; break; } @@ -1528,14 +1530,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_BOTTOM_LEFT: case PRESET_CENTER_LEFT: case PRESET_LEFT_WIDE: - data.margin[2] = x * (0.0 - data.anchor[2]) + new_size.x + p_margin + parent_rect.position.x; + data.offset[2] = x * (0.0 - data.anchor[2]) + new_size.x + p_margin + parent_rect.position.x; break; case PRESET_CENTER_TOP: case PRESET_CENTER_BOTTOM: case PRESET_CENTER: case PRESET_VCENTER_WIDE: - data.margin[2] = x * (0.5 - data.anchor[2]) + new_size.x / 2 + parent_rect.position.x; + data.offset[2] = x * (0.5 - data.anchor[2]) + new_size.x / 2 + parent_rect.position.x; break; case PRESET_TOP_RIGHT: @@ -1546,7 +1548,7 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_BOTTOM_WIDE: case PRESET_HCENTER_WIDE: case PRESET_WIDE: - data.margin[2] = x * (1.0 - data.anchor[2]) - p_margin + parent_rect.position.x; + data.offset[2] = x * (1.0 - data.anchor[2]) - p_margin + parent_rect.position.x; break; } @@ -1556,14 +1558,14 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_TOP_RIGHT: case PRESET_CENTER_TOP: case PRESET_TOP_WIDE: - data.margin[3] = parent_rect.size.y * (0.0 - data.anchor[3]) + new_size.y + p_margin + parent_rect.position.y; + data.offset[3] = parent_rect.size.y * (0.0 - data.anchor[3]) + new_size.y + p_margin + parent_rect.position.y; break; case PRESET_CENTER_LEFT: case PRESET_CENTER_RIGHT: case PRESET_CENTER: case PRESET_HCENTER_WIDE: - data.margin[3] = parent_rect.size.y * (0.5 - data.anchor[3]) + new_size.y / 2 + parent_rect.position.y; + data.offset[3] = parent_rect.size.y * (0.5 - data.anchor[3]) + new_size.y / 2 + parent_rect.position.y; break; case PRESET_BOTTOM_LEFT: @@ -1574,65 +1576,55 @@ void Control::set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resiz case PRESET_BOTTOM_WIDE: case PRESET_VCENTER_WIDE: case PRESET_WIDE: - data.margin[3] = parent_rect.size.y * (1.0 - data.anchor[3]) - p_margin + parent_rect.position.y; + data.offset[3] = parent_rect.size.y * (1.0 - data.anchor[3]) - p_margin + parent_rect.position.y; break; } _size_changed(); } -void Control::set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { +void Control::set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode, int p_margin) { set_anchors_preset(p_preset); - set_margins_preset(p_preset, p_resize_mode, p_margin); + set_offsets_preset(p_preset, p_resize_mode, p_margin); } -float Control::get_anchor(Margin p_margin) const { - ERR_FAIL_INDEX_V(int(p_margin), 4, 0.0); +real_t Control::get_anchor(Side p_side) const { + ERR_FAIL_INDEX_V(int(p_side), 4, 0.0); - return data.anchor[p_margin]; + return data.anchor[p_side]; } -void Control::_change_notify_margins() { - // this avoids sending the whole object data again on a change - _change_notify("margin_left"); - _change_notify("margin_top"); - _change_notify("margin_right"); - _change_notify("margin_bottom"); - _change_notify("rect_position"); - _change_notify("rect_size"); -} +void Control::set_offset(Side p_side, real_t p_value) { + ERR_FAIL_INDEX((int)p_side, 4); -void Control::set_margin(Margin p_margin, float p_value) { - ERR_FAIL_INDEX((int)p_margin, 4); - - data.margin[p_margin] = p_value; + data.offset[p_side] = p_value; _size_changed(); } void Control::set_begin(const Size2 &p_point) { - data.margin[0] = p_point.x; - data.margin[1] = p_point.y; + data.offset[0] = p_point.x; + data.offset[1] = p_point.y; _size_changed(); } void Control::set_end(const Size2 &p_point) { - data.margin[2] = p_point.x; - data.margin[3] = p_point.y; + data.offset[2] = p_point.x; + data.offset[3] = p_point.y; _size_changed(); } -float Control::get_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); +real_t Control::get_offset(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); - return data.margin[p_margin]; + return data.offset[p_side]; } Size2 Control::get_begin() const { - return Size2(data.margin[0], data.margin[1]); + return Size2(data.offset[0], data.offset[1]); } Size2 Control::get_end() const { - return Size2(data.margin[2], data.margin[3]); + return Size2(data.offset[2], data.offset[3]); } Point2 Control::get_global_position() const { @@ -1654,57 +1646,53 @@ void Control::_set_global_position(const Point2 &p_point) { set_global_position(p_point); } -void Control::set_global_position(const Point2 &p_point, bool p_keep_margins) { +void Control::set_global_position(const Point2 &p_point, bool p_keep_offsets) { Transform2D inv; if (data.parent_canvas_item) { inv = data.parent_canvas_item->get_global_transform().affine_inverse(); } - set_position(inv.xform(p_point), p_keep_margins); + set_position(inv.xform(p_point), p_keep_offsets); } -void Control::_compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]) { +void Control::_compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]) { Size2 parent_rect_size = get_parent_anchorable_rect().size; ERR_FAIL_COND(parent_rect_size.x == 0.0); ERR_FAIL_COND(parent_rect_size.y == 0.0); - float x = p_rect.position.x; + real_t x = p_rect.position.x; if (is_layout_rtl()) { x = parent_rect_size.x - x - p_rect.size.x; } - r_anchors[0] = (x - p_margins[0]) / parent_rect_size.x; - r_anchors[1] = (p_rect.position.y - p_margins[1]) / parent_rect_size.y; - r_anchors[2] = (x + p_rect.size.x - p_margins[2]) / parent_rect_size.x; - r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_margins[3]) / parent_rect_size.y; + r_anchors[0] = (x - p_offsets[0]) / parent_rect_size.x; + r_anchors[1] = (p_rect.position.y - p_offsets[1]) / parent_rect_size.y; + r_anchors[2] = (x + p_rect.size.x - p_offsets[2]) / parent_rect_size.x; + r_anchors[3] = (p_rect.position.y + p_rect.size.y - p_offsets[3]) / parent_rect_size.y; } -void Control::_compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]) { +void Control::_compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]) { Size2 parent_rect_size = get_parent_anchorable_rect().size; - float x = p_rect.position.x; + real_t x = p_rect.position.x; if (is_layout_rtl()) { x = parent_rect_size.x - x - p_rect.size.x; } - r_margins[0] = x - (p_anchors[0] * parent_rect_size.x); - r_margins[1] = p_rect.position.y - (p_anchors[1] * parent_rect_size.y); - r_margins[2] = x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x); - r_margins[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y); + r_offsets[0] = x - (p_anchors[0] * parent_rect_size.x); + r_offsets[1] = p_rect.position.y - (p_anchors[1] * parent_rect_size.y); + r_offsets[2] = x + p_rect.size.x - (p_anchors[2] * parent_rect_size.x); + r_offsets[3] = p_rect.position.y + p_rect.size.y - (p_anchors[3] * parent_rect_size.y); } void Control::_set_position(const Size2 &p_point) { set_position(p_point); } -void Control::set_position(const Size2 &p_point, bool p_keep_margins) { - if (p_keep_margins) { - _compute_anchors(Rect2(p_point, data.size_cache), data.margin, data.anchor); - _change_notify("anchor_left"); - _change_notify("anchor_right"); - _change_notify("anchor_top"); - _change_notify("anchor_bottom"); +void Control::set_position(const Size2 &p_point, bool p_keep_offsets) { + if (p_keep_offsets) { + _compute_anchors(Rect2(p_point, data.size_cache), data.offset, data.anchor); } else { - _compute_margins(Rect2(p_point, data.size_cache), data.anchor, data.margin); + _compute_offsets(Rect2(p_point, data.size_cache), data.anchor, data.offset); } _size_changed(); } @@ -1714,17 +1702,22 @@ void Control::set_rect(const Rect2 &p_rect) { data.anchor[i] = ANCHOR_BEGIN; } - _compute_margins(p_rect, data.anchor, data.margin); + _compute_offsets(p_rect, data.anchor, data.offset); if (is_inside_tree()) { _size_changed(); } } void Control::_set_size(const Size2 &p_size) { +#ifdef DEBUG_ENABLED + if (data.size_warning) { + WARN_PRINT("Adjusting the size of Control nodes before they are fully initialized is unreliable. Consider deferring it with set_deferred()."); + } +#endif set_size(p_size); } -void Control::set_size(const Size2 &p_size, bool p_keep_margins) { +void Control::set_size(const Size2 &p_size, bool p_keep_offsets) { Size2 new_size = p_size; Size2 min = get_combined_minimum_size(); if (new_size.x < min.x) { @@ -1734,14 +1727,10 @@ void Control::set_size(const Size2 &p_size, bool p_keep_margins) { new_size.y = min.y; } - if (p_keep_margins) { - _compute_anchors(Rect2(data.pos_cache, new_size), data.margin, data.anchor); - _change_notify("anchor_left"); - _change_notify("anchor_right"); - _change_notify("anchor_top"); - _change_notify("anchor_bottom"); + if (p_keep_offsets) { + _compute_anchors(Rect2(data.pos_cache, new_size), data.offset, data.anchor); } else { - _compute_margins(Rect2(data.pos_cache, new_size), data.anchor, data.margin); + _compute_offsets(Rect2(data.pos_cache, new_size), data.anchor, data.offset); } _size_changed(); } @@ -1791,7 +1780,7 @@ void Control::add_theme_icon_override(const StringName &p_name, const Ref<Textur data.icon_override[p_name]->disconnect("changed", callable_mp(this, &Control::_override_changed)); } - // clear if "null" is passed instead of a icon + // clear if "null" is passed instead of an icon if (p_icon.is_null()) { data.icon_override.erase(p_name); } else { @@ -2206,14 +2195,14 @@ String Control::_get_tooltip() const { return data.tooltip; } -void Control::set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor) { - ERR_FAIL_INDEX((int)p_margin, 4); - data.focus_neighbor[p_margin] = p_neighbor; +void Control::set_focus_neighbor(Side p_side, const NodePath &p_neighbor) { + ERR_FAIL_INDEX((int)p_side, 4); + data.focus_neighbor[p_side] = p_neighbor; } -NodePath Control::get_focus_neighbor(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, NodePath()); - return data.focus_neighbor[p_margin]; +NodePath Control::get_focus_neighbor(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, NodePath()); + return data.focus_neighbor[p_side]; } void Control::set_focus_next(const NodePath &p_next) { @@ -2234,15 +2223,15 @@ NodePath Control::get_focus_previous() const { #define MAX_NEIGHBOR_SEARCH_COUNT 512 -Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) { - ERR_FAIL_INDEX_V((int)p_margin, 4, nullptr); +Control *Control::_get_focus_neighbor(Side p_side, int p_count) { + ERR_FAIL_INDEX_V((int)p_side, 4, nullptr); if (p_count >= MAX_NEIGHBOR_SEARCH_COUNT) { return nullptr; } - if (!data.focus_neighbor[p_margin].is_empty()) { + if (!data.focus_neighbor[p_side].is_empty()) { Control *c = nullptr; - Node *n = get_node(data.focus_neighbor[p_margin]); + Node *n = get_node(data.focus_neighbor[p_side]); if (n) { c = Object::cast_to<Control>(n); ERR_FAIL_COND_V_MSG(!c, nullptr, "Neighbor focus node is not a control: " + n->get_name() + "."); @@ -2260,11 +2249,11 @@ Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) { return c; } - c = c->_get_focus_neighbor(p_margin, p_count + 1); + c = c->_get_focus_neighbor(p_side, p_count + 1); return c; } - float dist = 1e7; + real_t dist = 1e7; Control *result = nullptr; Point2 points[4]; @@ -2283,12 +2272,12 @@ Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) { Vector2(0, 1) }; - Vector2 vdir = dir[p_margin]; + Vector2 vdir = dir[p_side]; - float maxd = -1e7; + real_t maxd = -1e7; for (int i = 0; i < 4; i++) { - float d = vdir.dot(points[i]); + real_t d = vdir.dot(points[i]); if (d > maxd) { maxd = d; } @@ -2315,7 +2304,7 @@ Control *Control::_get_focus_neighbor(Margin p_margin, int p_count) { return result; } -void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest) { +void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest) { if (Object::cast_to<Viewport>(p_at)) { return; //bye } @@ -2332,10 +2321,10 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons points[2] = xform.xform(c->get_size()); points[3] = xform.xform(Point2(0, c->get_size().y)); - float min = 1e7; + real_t min = 1e7; for (int i = 0; i < 4; i++) { - float d = p_dir.dot(points[i]); + real_t d = p_dir.dot(points[i]); if (d < min) { min = d; } @@ -2351,8 +2340,8 @@ void Control::_window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, cons Vector2 fb = points[(j + 1) % 4]; Vector2 pa, pb; - float d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb); - //float d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0)); + real_t d = Geometry2D::get_closest_points_between_segments(la, lb, fa, fb, pa, pb); + //real_t d = Geometry2D::get_closest_distance_between_segments(Vector3(la.x,la.y,0),Vector3(lb.x,lb.y,0),Vector3(fa.x,fa.y,0),Vector3(fb.x,fb.y,0)); if (d < r_closest_dist) { r_closest_dist = d; *r_closest = c; @@ -2392,7 +2381,7 @@ void Control::set_v_size_flags(int p_flags) { emit_signal(SceneStringNames::get_singleton()->size_flags_changed); } -void Control::set_stretch_ratio(float p_ratio) { +void Control::set_stretch_ratio(real_t p_ratio) { if (data.expand == p_ratio) { return; } @@ -2401,7 +2390,7 @@ void Control::set_stretch_ratio(float p_ratio) { emit_signal(SceneStringNames::get_singleton()->size_flags_changed); } -float Control::get_stretch_ratio() const { +real_t Control::get_stretch_ratio() const { return data.expand; } @@ -2573,22 +2562,21 @@ Vector<Vector2i> Control::structured_text_parser(StructuredTextParser p_node_typ return ret; } -void Control::set_rotation(float p_radians) { +void Control::set_rotation(real_t p_radians) { data.rotation = p_radians; update(); _notify_transform(); - _change_notify("rect_rotation"); } -float Control::get_rotation() const { +real_t Control::get_rotation() const { return data.rotation; } -void Control::set_rotation_degrees(float p_degrees) { +void Control::set_rotation_degrees(real_t p_degrees) { set_rotation(Math::deg2rad(p_degrees)); } -float Control::get_rotation_degrees() const { +real_t Control::get_rotation_degrees() const { return Math::rad2deg(get_rotation()); } @@ -2602,7 +2590,6 @@ void Control::set_pivot_offset(const Vector2 &p_pivot) { data.pivot_offset = p_pivot; update(); _notify_transform(); - _change_notify("rect_pivot_offset"); } Vector2 Control::get_pivot_offset() const { @@ -2698,7 +2685,7 @@ String Control::get_configuration_warning() const { String warning = CanvasItem::get_configuration_warning(); if (data.mouse_filter == MOUSE_FILTER_IGNORE && data.tooltip != "") { - if (!warning.empty()) { + if (!warning.is_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\"."); @@ -2745,28 +2732,28 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("accept_event"), &Control::accept_event); ClassDB::bind_method(D_METHOD("get_minimum_size"), &Control::get_minimum_size); ClassDB::bind_method(D_METHOD("get_combined_minimum_size"), &Control::get_combined_minimum_size); - ClassDB::bind_method(D_METHOD("set_anchors_preset", "preset", "keep_margins"), &Control::set_anchors_preset, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("set_margins_preset", "preset", "resize_mode", "margin"), &Control::set_margins_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("set_anchors_and_margins_preset", "preset", "resize_mode", "margin"), &Control::set_anchors_and_margins_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); - ClassDB::bind_method(D_METHOD("_set_anchor", "margin", "anchor"), &Control::_set_anchor); - ClassDB::bind_method(D_METHOD("set_anchor", "margin", "anchor", "keep_margin", "push_opposite_anchor"), &Control::set_anchor, DEFVAL(false), DEFVAL(true)); - ClassDB::bind_method(D_METHOD("get_anchor", "margin"), &Control::get_anchor); - ClassDB::bind_method(D_METHOD("set_margin", "margin", "offset"), &Control::set_margin); - ClassDB::bind_method(D_METHOD("set_anchor_and_margin", "margin", "anchor", "offset", "push_opposite_anchor"), &Control::set_anchor_and_margin, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_anchors_preset", "preset", "keep_offsets"), &Control::set_anchors_preset, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_offsets_preset", "preset", "resize_mode", "margin"), &Control::set_offsets_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("set_anchors_and_offsets_preset", "preset", "resize_mode", "margin"), &Control::set_anchors_and_offsets_preset, DEFVAL(PRESET_MODE_MINSIZE), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("_set_anchor", "side", "anchor"), &Control::_set_anchor); + ClassDB::bind_method(D_METHOD("set_anchor", "side", "anchor", "keep_offset", "push_opposite_anchor"), &Control::set_anchor, DEFVAL(false), DEFVAL(true)); + ClassDB::bind_method(D_METHOD("get_anchor", "side"), &Control::get_anchor); + ClassDB::bind_method(D_METHOD("set_offset", "side", "offset"), &Control::set_offset); + ClassDB::bind_method(D_METHOD("set_anchor_and_offset", "side", "anchor", "offset", "push_opposite_anchor"), &Control::set_anchor_and_offset, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_begin", "position"), &Control::set_begin); ClassDB::bind_method(D_METHOD("set_end", "position"), &Control::set_end); - ClassDB::bind_method(D_METHOD("set_position", "position", "keep_margins"), &Control::set_position, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("_set_position", "margin"), &Control::_set_position); - ClassDB::bind_method(D_METHOD("set_size", "size", "keep_margins"), &Control::set_size, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_position", "position", "keep_offsets"), &Control::set_position, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("_set_position", "position"), &Control::_set_position); + ClassDB::bind_method(D_METHOD("set_size", "size", "keep_offsets"), &Control::set_size, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_set_size", "size"), &Control::_set_size); ClassDB::bind_method(D_METHOD("set_custom_minimum_size", "size"), &Control::set_custom_minimum_size); - ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_margins"), &Control::set_global_position, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("set_global_position", "position", "keep_offsets"), &Control::set_global_position, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_set_global_position", "position"), &Control::_set_global_position); ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Control::set_rotation); ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Control::set_rotation_degrees); ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Control::set_scale); ClassDB::bind_method(D_METHOD("set_pivot_offset", "pivot_offset"), &Control::set_pivot_offset); - ClassDB::bind_method(D_METHOD("get_margin", "margin"), &Control::get_margin); + ClassDB::bind_method(D_METHOD("get_offset", "offset"), &Control::get_offset); ClassDB::bind_method(D_METHOD("get_begin"), &Control::get_begin); ClassDB::bind_method(D_METHOD("get_end"), &Control::get_end); ClassDB::bind_method(D_METHOD("get_position"), &Control::get_position); @@ -2785,6 +2772,8 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("has_focus"), &Control::has_focus); ClassDB::bind_method(D_METHOD("grab_focus"), &Control::grab_focus); ClassDB::bind_method(D_METHOD("release_focus"), &Control::release_focus); + ClassDB::bind_method(D_METHOD("find_prev_valid_focus"), &Control::find_prev_valid_focus); + ClassDB::bind_method(D_METHOD("find_next_valid_focus"), &Control::find_next_valid_focus); ClassDB::bind_method(D_METHOD("get_focus_owner"), &Control::get_focus_owner); ClassDB::bind_method(D_METHOD("set_h_size_flags", "flags"), &Control::set_h_size_flags); @@ -2843,8 +2832,8 @@ void Control::_bind_methods() { ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape); ClassDB::bind_method(D_METHOD("get_cursor_shape", "position"), &Control::get_cursor_shape, DEFVAL(Point2())); - ClassDB::bind_method(D_METHOD("set_focus_neighbor", "margin", "neighbor"), &Control::set_focus_neighbor); - ClassDB::bind_method(D_METHOD("get_focus_neighbor", "margin"), &Control::get_focus_neighbor); + ClassDB::bind_method(D_METHOD("set_focus_neighbor", "side", "neighbor"), &Control::set_focus_neighbor); + ClassDB::bind_method(D_METHOD("get_focus_neighbor", "side"), &Control::get_focus_neighbor); ClassDB::bind_method(D_METHOD("set_focus_next", "next"), &Control::set_focus_next); ClassDB::bind_method(D_METHOD("get_focus_next"), &Control::get_focus_next); @@ -2890,16 +2879,16 @@ void Control::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::BOOL, "_clips_input")); ADD_GROUP("Anchor", "anchor_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_left", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_top", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_right", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "anchor_bottom", PROPERTY_HINT_RANGE, "0,1,0.001,or_lesser,or_greater"), "_set_anchor", "get_anchor", SIDE_BOTTOM); - ADD_GROUP("Margin", "margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_top", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_right", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "margin_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_BOTTOM); + ADD_GROUP("Offset", "offset_"); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_left", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_top", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_right", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "offset_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_offset", "get_offset", SIDE_BOTTOM); ADD_GROUP("Grow Direction", "grow_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_h_grow_direction", "get_h_grow_direction"); @@ -2913,7 +2902,8 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "_set_global_position", "get_global_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_rotation_degrees", "get_rotation_degrees"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rect_rotation_degrees", PROPERTY_HINT_RANGE, "-360,360,0.1,or_lesser,or_greater"), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents"); @@ -2922,10 +2912,10 @@ void Control::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip"); ADD_GROUP("Focus", "focus_"); - ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_top", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_right", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_bottom", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_BOTTOM); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_next", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_next", "get_focus_next"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "focus_previous", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_previous", "get_focus_previous"); ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode"); diff --git a/scene/gui/control.h b/scene/gui/control.h index 2241c242bb..a911d69c3f 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -171,21 +171,22 @@ private: Size2 last_minimum_size; bool updating_last_minimum_size = false; - float margin[4] = { 0.0, 0.0, 0.0, 0.0 }; - float anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN }; + real_t offset[4] = { 0.0, 0.0, 0.0, 0.0 }; + real_t anchor[4] = { ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN, ANCHOR_BEGIN }; FocusMode focus_mode = FOCUS_NONE; GrowDirection h_grow = GROW_DIRECTION_END; GrowDirection v_grow = GROW_DIRECTION_END; LayoutDirection layout_dir = LAYOUT_DIRECTION_INHERITED; - float rotation = 0; + real_t rotation = 0.0; Vector2 scale = Vector2(1, 1); Vector2 pivot_offset; + bool size_warning = true; int h_size_flags = SIZE_FILL; int v_size_flags = SIZE_FILL; - float expand = 1; + real_t expand = 1.0; Point2 custom_minimum_size; MouseFilter mouse_filter = MOUSE_FILTER_STOP; @@ -223,23 +224,23 @@ private: // used internally Control *_find_control_at_pos(CanvasItem *p_node, const Point2 &p_pos, const Transform2D &p_xform, Transform2D &r_inv_xform); - void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, float p_min, float &r_closest_dist, Control **r_closest); - Control *_get_focus_neighbor(Margin p_margin, int p_count = 0); + void _window_find_focus_neighbor(const Vector2 &p_dir, Node *p_at, const Point2 *p_points, real_t p_min, real_t &r_closest_dist, Control **r_closest); + Control *_get_focus_neighbor(Side p_side, int p_count = 0); - void _set_anchor(Margin p_margin, float p_anchor); + void _set_anchor(Side p_side, real_t p_anchor); void _set_position(const Point2 &p_point); void _set_global_position(const Point2 &p_point); void _set_size(const Size2 &p_size); void _theme_changed(); - void _change_notify_margins(); void _update_minimum_size(); + void _clear_size_warning(); void _update_scroll(); - void _compute_margins(Rect2 p_rect, const float p_anchors[4], float (&r_margins)[4]); - void _compute_anchors(Rect2 p_rect, const float p_margins[4], float (&r_anchors)[4]); + void _compute_offsets(Rect2 p_rect, const real_t p_anchors[4], real_t (&r_offsets)[4]); + void _compute_anchors(Rect2 p_rect, const real_t p_offsets[4], real_t (&r_anchors)[4]); void _size_changed(); String _get_tooltip() const; @@ -324,8 +325,8 @@ public: virtual Rect2 _edit_get_rect() const override; virtual bool _edit_use_rect() const override; - virtual void _edit_set_rotation(float p_rotation) override; - virtual float _edit_get_rotation() const override; + virtual void _edit_set_rotation(real_t p_rotation) override; + virtual real_t _edit_get_rotation() const override; virtual bool _edit_use_rotation() const override; virtual void _edit_set_pivot(const Point2 &p_pivot) override; @@ -359,17 +360,17 @@ public: /* POSITIONING */ - void set_anchors_preset(LayoutPreset p_preset, bool p_keep_margins = true); - void set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); - void set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); + void set_anchors_preset(LayoutPreset p_preset, bool p_keep_offsets = true); + void set_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); + void set_anchors_and_offsets_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0); - void set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin = true, bool p_push_opposite_anchor = true); - float get_anchor(Margin p_margin) const; + void set_anchor(Side p_side, real_t p_anchor, bool p_keep_offset = true, bool p_push_opposite_anchor = true); + real_t get_anchor(Side p_side) const; - void set_margin(Margin p_margin, float p_value); - float get_margin(Margin p_margin) const; + void set_offset(Side p_side, real_t p_value); + real_t get_offset(Side p_side) const; - void set_anchor_and_margin(Margin p_margin, float p_anchor, float p_pos, bool p_push_opposite_anchor = true); + void set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos, bool p_push_opposite_anchor = true); void set_begin(const Point2 &p_point); // helper void set_end(const Point2 &p_point); // helper @@ -377,13 +378,13 @@ public: Point2 get_begin() const; Point2 get_end() const; - void set_position(const Point2 &p_point, bool p_keep_margins = false); - void set_global_position(const Point2 &p_point, bool p_keep_margins = false); + void set_position(const Point2 &p_point, bool p_keep_offsets = false); + void set_global_position(const Point2 &p_point, bool p_keep_offsets = false); Point2 get_position() const; Point2 get_global_position() const; Point2 get_screen_position() const; - void set_size(const Size2 &p_size, bool p_keep_margins = false); + void set_size(const Size2 &p_size, bool p_keep_offsets = false); Size2 get_size() const; Rect2 get_rect() const; @@ -394,10 +395,10 @@ public: void set_rect(const Rect2 &p_rect); // Reset anchors to begin and set rect, for faster container children sorting. - void set_rotation(float p_radians); - void set_rotation_degrees(float p_degrees); - float get_rotation() const; - float get_rotation_degrees() const; + void set_rotation(real_t p_radians); + void set_rotation_degrees(real_t p_degrees); + real_t get_rotation() const; + real_t get_rotation_degrees() const; void set_h_grow_direction(GrowDirection p_direction); GrowDirection get_h_grow_direction() const; @@ -420,8 +421,8 @@ public: void set_v_size_flags(int p_flags); int get_v_size_flags() const; - void set_stretch_ratio(float p_ratio); - float get_stretch_ratio() const; + void set_stretch_ratio(real_t p_ratio); + real_t get_stretch_ratio() const; void minimum_size_changed(); @@ -436,8 +437,8 @@ public: Control *find_next_valid_focus() const; Control *find_prev_valid_focus() const; - void set_focus_neighbor(Margin p_margin, const NodePath &p_neighbor); - NodePath get_focus_neighbor(Margin p_margin) const; + void set_focus_neighbor(Side p_side, const NodePath &p_neighbor); + NodePath get_focus_neighbor(Side p_side) const; void set_focus_next(const NodePath &p_next); NodePath get_focus_next() const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 4e80498108..b6884bd37d 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -165,7 +165,7 @@ void AcceptDialog::register_text_enter(Node *p_line_edit) { void AcceptDialog::_update_child_rects() { Size2 label_size = label->get_minimum_size(); - if (label->get_text().empty()) { + if (label->get_text().is_empty()) { label_size.height = 0; } int margin = hbc->get_theme_constant("margin", "Dialogs"); @@ -256,7 +256,7 @@ Button *AcceptDialog::add_button(const String &p_text, bool p_right, const Strin Button *AcceptDialog::add_cancel_button(const String &p_cancel) { String c = p_cancel; if (p_cancel == "") { - c = RTR("Cancel"); + c = TTRC("Cancel"); } Button *b = swap_cancel_ok ? add_button(c, true) : add_button(c); b->connect("pressed", callable_mp(this, &AcceptDialog::_cancel_pressed)); @@ -292,8 +292,6 @@ void AcceptDialog::set_swap_cancel_ok(bool p_swap) { } AcceptDialog::AcceptDialog() { - parent_visible = nullptr; - set_wrap_controls(true); set_visible(false); set_transient(true); @@ -309,8 +307,8 @@ AcceptDialog::AcceptDialog() { int button_margin = hbc->get_theme_constant("button_margin", "Dialogs"); label = memnew(Label); - label->set_anchor(MARGIN_RIGHT, Control::ANCHOR_END); - label->set_anchor(MARGIN_BOTTOM, Control::ANCHOR_END); + label->set_anchor(SIDE_RIGHT, Control::ANCHOR_END); + label->set_anchor(SIDE_BOTTOM, Control::ANCHOR_END); label->set_begin(Point2(margin, margin)); label->set_end(Point2(-margin, -button_margin - 10)); add_child(label); @@ -319,14 +317,13 @@ AcceptDialog::AcceptDialog() { hbc->add_spacer(); ok = memnew(Button); - ok->set_text(RTR("OK")); + ok->set_text(TTRC("OK")); hbc->add_child(ok); hbc->add_spacer(); ok->connect("pressed", callable_mp(this, &AcceptDialog::_ok_pressed)); - hide_on_ok = true; - set_title(RTR("Alert!")); + set_title(TTRC("Alert!")); connect("window_input", callable_mp(this, &AcceptDialog::_input_from_window)); } @@ -345,7 +342,7 @@ Button *ConfirmationDialog::get_cancel_button() { } ConfirmationDialog::ConfirmationDialog() { - set_title(RTR("Please Confirm...")); + set_title(TTRC("Please Confirm...")); #ifdef TOOLS_ENABLED set_min_size(Size2(200, 70) * EDSCALE); #endif diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h index 8f6e0e86f9..b072055d49 100644 --- a/scene/gui/dialogs.h +++ b/scene/gui/dialogs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,12 +44,12 @@ class LineEdit; class AcceptDialog : public Window { GDCLASS(AcceptDialog, Window); - Window *parent_visible; + Window *parent_visible = nullptr; Panel *bg; HBoxContainer *hbc; Label *label; Button *ok; - bool hide_on_ok; + bool hide_on_ok = true; void _custom_action(const String &p_action); void _update_child_rects(); diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 041b8ef174..7ac8dbccca 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,20 +50,28 @@ VBoxContainer *FileDialog::get_vbox() { void FileDialog::_theme_changed() { Color font_color = vbox->get_theme_color("font_color", "Button"); - Color font_color_hover = vbox->get_theme_color("font_color_hover", "Button"); - Color font_color_pressed = vbox->get_theme_color("font_color_pressed", "Button"); + Color font_hover_color = vbox->get_theme_color("font_hover_color", "Button"); + Color font_pressed_color = vbox->get_theme_color("font_pressed_color", "Button"); - dir_up->add_theme_color_override("icon_color_normal", font_color); - dir_up->add_theme_color_override("icon_color_hover", font_color_hover); - dir_up->add_theme_color_override("icon_color_pressed", font_color_pressed); + dir_up->add_theme_color_override("icon_normal_color", font_color); + dir_up->add_theme_color_override("icon_hover_color", font_hover_color); + dir_up->add_theme_color_override("icon_pressed_color", font_pressed_color); - refresh->add_theme_color_override("icon_color_normal", font_color); - refresh->add_theme_color_override("icon_color_hover", font_color_hover); - refresh->add_theme_color_override("icon_color_pressed", font_color_pressed); + dir_prev->add_theme_color_override("icon_color_normal", font_color); + dir_prev->add_theme_color_override("icon_color_hover", font_hover_color); + dir_prev->add_theme_color_override("icon_color_pressed", font_pressed_color); - show_hidden->add_theme_color_override("icon_color_normal", font_color); - show_hidden->add_theme_color_override("icon_color_hover", font_color_hover); - show_hidden->add_theme_color_override("icon_color_pressed", font_color_pressed); + dir_next->add_theme_color_override("icon_color_normal", font_color); + dir_next->add_theme_color_override("icon_color_hover", font_hover_color); + dir_next->add_theme_color_override("icon_color_pressed", font_pressed_color); + + refresh->add_theme_color_override("icon_normal_color", font_color); + refresh->add_theme_color_override("icon_hover_color", font_hover_color); + refresh->add_theme_color_override("icon_pressed_color", font_pressed_color); + + show_hidden->add_theme_color_override("icon_normal_color", font_color); + show_hidden->add_theme_color_override("icon_hover_color", font_hover_color); + show_hidden->add_theme_color_override("icon_pressed_color", font_pressed_color); } void FileDialog::_notification(int p_what) { @@ -74,6 +82,13 @@ void FileDialog::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE) { dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog")); + if (vbox->is_layout_rtl()) { + dir_prev->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog")); + dir_next->set_icon(vbox->get_theme_icon("back_folder", "FileDialog")); + } else { + dir_prev->set_icon(vbox->get_theme_icon("back_folder", "FileDialog")); + dir_next->set_icon(vbox->get_theme_icon("forward_folder", "FileDialog")); + } refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog")); show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog")); _theme_changed(); @@ -136,7 +151,7 @@ void FileDialog::update_dir() { } // Deselect any item, to make "Select Current Folder" button text by default. - deselect_items(); + deselect_all(); } void FileDialog::_dir_entered(String p_dir) { @@ -144,6 +159,7 @@ void FileDialog::_dir_entered(String p_dir) { file->set_text(""); invalidate(); update_dir(); + _push_history(); } void FileDialog::_file_entered(const String &p_file) { @@ -172,11 +188,26 @@ void FileDialog::_post_popup() { // For open dir mode, deselect all items on file dialog open. if (mode == FILE_MODE_OPEN_DIR) { - deselect_items(); + deselect_all(); file_box->set_visible(false); } else { file_box->set_visible(true); } + + local_history.clear(); + local_history_pos = -1; + _push_history(); +} + +void FileDialog::_push_history() { + local_history.resize(local_history_pos + 1); + String new_path = dir_access->get_current_dir(); + if (local_history.size() == 0 || new_path != local_history[local_history_pos]) { + local_history.push_back(new_path); + local_history_pos++; + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(true); + } } void FileDialog::_action_pressed() { @@ -272,7 +303,7 @@ void FileDialog::_action_pressed() { } if (dir_access->file_exists(f)) { - confirm_save->set_text(RTR("File exists, overwrite?")); + confirm_save->set_text(TTRC("File exists, overwrite?")); confirm_save->popup_centered(Size2(200, 80)); } else { emit_signal("file_selected", f); @@ -316,9 +347,38 @@ void FileDialog::_go_up() { dir_access->change_dir(".."); update_file_list(); update_dir(); + _push_history(); } -void FileDialog::deselect_items() { +void FileDialog::_go_back() { + if (local_history_pos <= 0) { + return; + } + + local_history_pos--; + dir_access->change_dir(local_history[local_history_pos]); + update_file_list(); + update_dir(); + + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(local_history_pos == local_history.size() - 1); +} + +void FileDialog::_go_forward() { + if (local_history_pos == local_history.size() - 1) { + return; + } + + local_history_pos++; + dir_access->change_dir(local_history[local_history_pos]); + update_file_list(); + update_dir(); + + dir_prev->set_disabled(local_history_pos == 0); + dir_next->set_disabled(local_history_pos == local_history.size() - 1); +} + +void FileDialog::deselect_all() { // Clear currently selected items in file manager. tree->deselect_all(); @@ -329,10 +389,10 @@ void FileDialog::deselect_items() { switch (mode) { case FILE_MODE_OPEN_FILE: case FILE_MODE_OPEN_FILES: - get_ok_button()->set_text(RTR("Open")); + get_ok_button()->set_text(TTRC("Open")); break; case FILE_MODE_OPEN_DIR: - get_ok_button()->set_text(RTR("Select Current Folder")); + get_ok_button()->set_text(TTRC("Select Current Folder")); break; case FILE_MODE_OPEN_ANY: case FILE_MODE_SAVE_FILE: @@ -356,7 +416,7 @@ void FileDialog::_tree_selected() { if (!d["dir"]) { file->set_text(d["name"]); } else if (mode == FILE_MODE_OPEN_DIR) { - get_ok_button()->set_text(RTR("Select This Folder")); + get_ok_button()->set_text(TTRC("Select This Folder")); } get_ok_button()->set_disabled(_is_open_should_be_disabled()); @@ -377,6 +437,7 @@ void FileDialog::_tree_item_activated() { } call_deferred("_update_file_list"); call_deferred("_update_dir"); + _push_history(); } else { _action_pressed(); } @@ -415,6 +476,13 @@ void FileDialog::update_file_list() { bool is_hidden; String item; + if (dir_access->is_readable(dir_access->get_current_dir().utf8().get_data())) { + message->hide(); + } else { + message->set_text(TTRC("You don't have permission to access contents of this folder.")); + message->show(); + } + while ((item = dir_access->get_next()) != "") { if (item == "." || item == "..") { continue; @@ -434,7 +502,7 @@ void FileDialog::update_file_list() { dirs.sort_custom<NaturalNoCaseComparator>(); files.sort_custom<NaturalNoCaseComparator>(); - while (!dirs.empty()) { + while (!dirs.is_empty()) { String &dir_name = dirs.front()->get(); TreeItem *ti = tree->create_item(root); ti->set_text(0, dir_name); @@ -478,8 +546,8 @@ void FileDialog::update_file_list() { String base_dir = dir_access->get_current_dir(); - while (!files.empty()) { - bool match = patterns.empty(); + while (!files.is_empty()) { + bool match = patterns.is_empty(); String match_str; for (List<String>::Element *E = patterns.front(); E; E = E->next()) { @@ -549,7 +617,7 @@ void FileDialog::update_filters() { all_filters += ", ..."; } - filter->add_item(RTR("All Recognized") + " (" + all_filters + ")"); + filter->add_item(String(TTRC("All Recognized")) + " (" + all_filters + ")"); } for (int i = 0; i < filters.size(); i++) { String flt = filters[i].get_slice(";", 0).strip_edges(); @@ -561,7 +629,7 @@ void FileDialog::update_filters() { } } - filter->add_item(RTR("All Files (*)")); + filter->add_item(TTRC("All Files (*)")); } void FileDialog::clear_filters() { @@ -602,6 +670,7 @@ void FileDialog::set_current_dir(const String &p_dir) { dir_access->change_dir(p_dir); update_dir(); invalidate(); + _push_history(); } void FileDialog::set_current_file(const String &p_file) { @@ -646,37 +715,37 @@ void FileDialog::set_file_mode(FileMode p_mode) { mode = p_mode; switch (mode) { case FILE_MODE_OPEN_FILE: - get_ok_button()->set_text(RTR("Open")); + get_ok_button()->set_text(TTRC("Open")); if (mode_overrides_title) { - set_title(RTR("Open a File")); + set_title(TTRC("Open a File")); } makedir->hide(); break; case FILE_MODE_OPEN_FILES: - get_ok_button()->set_text(RTR("Open")); + get_ok_button()->set_text(TTRC("Open")); if (mode_overrides_title) { - set_title(RTR("Open File(s)")); + set_title(TTRC("Open File(s)")); } makedir->hide(); break; case FILE_MODE_OPEN_DIR: - get_ok_button()->set_text(RTR("Select Current Folder")); + get_ok_button()->set_text(TTRC("Select Current Folder")); if (mode_overrides_title) { - set_title(RTR("Open a Directory")); + set_title(TTRC("Open a Directory")); } makedir->show(); break; case FILE_MODE_OPEN_ANY: - get_ok_button()->set_text(RTR("Open")); + get_ok_button()->set_text(TTRC("Open")); if (mode_overrides_title) { - set_title(RTR("Open a File or Directory")); + set_title(TTRC("Open a File or Directory")); } makedir->show(); break; case FILE_MODE_SAVE_FILE: - get_ok_button()->set_text(RTR("Save")); + get_ok_button()->set_text(TTRC("Save")); if (mode_overrides_title) { - set_title(RTR("Save a File")); + set_title(TTRC("Save a File")); } makedir->show(); break; @@ -731,12 +800,13 @@ FileDialog::Access FileDialog::get_access() const { } void FileDialog::_make_dir_confirm() { - Error err = dir_access->make_dir(makedirname->get_text()); + Error err = dir_access->make_dir(makedirname->get_text().strip_edges()); if (err == OK) { - dir_access->change_dir(makedirname->get_text()); + dir_access->change_dir(makedirname->get_text().strip_edges()); invalidate(); update_filters(); update_dir(); + _push_history(); } else { mkdirerr->popup_centered(Size2(250, 50)); } @@ -754,6 +824,7 @@ void FileDialog::_select_drive(int p_idx) { file->set_text(""); invalidate(); update_dir(); + _push_history(); } void FileDialog::_update_drives() { @@ -808,7 +879,7 @@ void FileDialog::_bind_methods() { ClassDB::bind_method(D_METHOD("_update_file_name"), &FileDialog::update_file_name); ClassDB::bind_method(D_METHOD("_update_dir"), &FileDialog::update_dir); ClassDB::bind_method(D_METHOD("_update_file_list"), &FileDialog::update_file_list); - ClassDB::bind_method(D_METHOD("deselect_items"), &FileDialog::deselect_items); + ClassDB::bind_method(D_METHOD("deselect_all"), &FileDialog::deselect_all); ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate); @@ -852,24 +923,32 @@ void FileDialog::set_default_show_hidden_files(bool p_show) { FileDialog::FileDialog() { show_hidden_files = default_show_hidden_files; - mode_overrides_title = true; - vbox = memnew(VBoxContainer); add_child(vbox); vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); mode = FILE_MODE_SAVE_FILE; - set_title(RTR("Save a File")); + set_title(TTRC("Save a File")); HBoxContainer *hbc = memnew(HBoxContainer); + dir_prev = memnew(Button); + dir_prev->set_flat(true); + dir_prev->set_tooltip(TTRC("Go to previous folder.")); + dir_next = memnew(Button); + dir_next->set_flat(true); + dir_next->set_tooltip(TTRC("Go to next folder.")); dir_up = memnew(Button); dir_up->set_flat(true); - dir_up->set_tooltip(RTR("Go to parent folder.")); + dir_up->set_tooltip(TTRC("Go to parent folder.")); + hbc->add_child(dir_prev); + hbc->add_child(dir_next); hbc->add_child(dir_up); + dir_prev->connect("pressed", callable_mp(this, &FileDialog::_go_back)); + dir_next->connect("pressed", callable_mp(this, &FileDialog::_go_forward)); dir_up->connect("pressed", callable_mp(this, &FileDialog::_go_up)); - hbc->add_child(memnew(Label(RTR("Path:")))); + hbc->add_child(memnew(Label(TTRC("Path:")))); drives_container = memnew(HBoxContainer); hbc->add_child(drives_container); @@ -885,7 +964,7 @@ FileDialog::FileDialog() { refresh = memnew(Button); refresh->set_flat(true); - refresh->set_tooltip(RTR("Refresh files.")); + refresh->set_tooltip(TTRC("Refresh files.")); refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list)); hbc->add_child(refresh); @@ -893,7 +972,7 @@ FileDialog::FileDialog() { show_hidden->set_flat(true); show_hidden->set_toggle_mode(true); show_hidden->set_pressed(is_showing_hidden_files()); - show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files.")); + show_hidden->set_tooltip(TTRC("Toggle the visibility of hidden files.")); show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files)); hbc->add_child(show_hidden); @@ -901,17 +980,24 @@ FileDialog::FileDialog() { hbc->add_child(shortcuts_container); makedir = memnew(Button); - makedir->set_text(RTR("Create Folder")); + makedir->set_text(TTRC("Create Folder")); makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir)); hbc->add_child(makedir); vbox->add_child(hbc); tree = memnew(Tree); tree->set_hide_root(true); - vbox->add_margin_child(RTR("Directories & Files:"), tree, true); + vbox->add_margin_child(TTRC("Directories & Files:"), tree, true); + + message = memnew(Label); + message->hide(); + message->set_anchors_and_offsets_preset(Control::PRESET_WIDE); + message->set_align(Label::ALIGN_CENTER); + message->set_valign(Label::VALIGN_CENTER); + tree->add_child(message); file_box = memnew(HBoxContainer); - file_box->add_child(memnew(Label(RTR("File:")))); + file_box->add_child(memnew(Label(TTRC("File:")))); file = memnew(LineEdit); file->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); file->set_stretch_ratio(4); @@ -925,14 +1011,13 @@ FileDialog::FileDialog() { vbox->add_child(file_box); dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); - access = ACCESS_RESOURCES; _update_drives(); connect("confirmed", callable_mp(this, &FileDialog::_action_pressed)); tree->connect("multi_selected", callable_mp(this, &FileDialog::_tree_multi_selected), varray(), CONNECT_DEFERRED); tree->connect("cell_selected", callable_mp(this, &FileDialog::_tree_selected), varray(), CONNECT_DEFERRED); tree->connect("item_activated", callable_mp(this, &FileDialog::_tree_item_activated), varray()); - tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_items)); + tree->connect("nothing_selected", callable_mp(this, &FileDialog::deselect_all)); dir->connect("text_entered", callable_mp(this, &FileDialog::_dir_entered)); file->connect("text_entered", callable_mp(this, &FileDialog::_file_entered)); filter->connect("item_selected", callable_mp(this, &FileDialog::_filter_selected)); @@ -944,22 +1029,22 @@ FileDialog::FileDialog() { confirm_save->connect("confirmed", callable_mp(this, &FileDialog::_save_confirm_pressed)); makedialog = memnew(ConfirmationDialog); - makedialog->set_title(RTR("Create Folder")); + makedialog->set_title(TTRC("Create Folder")); VBoxContainer *makevb = memnew(VBoxContainer); makedialog->add_child(makevb); makedirname = memnew(LineEdit); makedirname->set_structured_text_bidi_override(Control::STRUCTURED_TEXT_FILE); - makevb->add_margin_child(RTR("Name:"), makedirname); + makevb->add_margin_child(TTRC("Name:"), makedirname); add_child(makedialog); makedialog->register_text_enter(makedirname); makedialog->connect("confirmed", callable_mp(this, &FileDialog::_make_dir_confirm)); mkdirerr = memnew(AcceptDialog); - mkdirerr->set_text(RTR("Could not create folder.")); + mkdirerr->set_text(TTRC("Could not create folder.")); add_child(mkdirerr); exterr = memnew(AcceptDialog); - exterr->set_text(RTR("Must use a valid extension.")); + exterr->set_text(TTRC("Must use a valid extension.")); add_child(exterr); update_filters(); @@ -967,7 +1052,6 @@ FileDialog::FileDialog() { set_hide_on_ok(false); - invalidated = true; if (register_func) { register_func(this); } diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 8003650668..4996f00cb3 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -69,7 +69,7 @@ private: LineEdit *makedirname; Button *makedir; - Access access; + Access access = ACCESS_RESOURCES; //Button *action; VBoxContainer *vbox; FileMode mode; @@ -86,6 +86,10 @@ private: DirAccess *dir_access; ConfirmationDialog *confirm_save; + Label *message; + + Button *dir_prev; + Button *dir_next; Button *dir_up; Button *refresh; @@ -93,12 +97,16 @@ private: Vector<String> filters; - bool mode_overrides_title; + Vector<String> local_history; + int local_history_pos = 0; + void _push_history(); + + bool mode_overrides_title = true; static bool default_show_hidden_files; - bool show_hidden_files; + bool show_hidden_files = false; - bool invalidated; + bool invalidated = true; void update_dir(); void update_file_name(); @@ -119,6 +127,8 @@ private: void _make_dir(); void _make_dir_confirm(); void _go_up(); + void _go_back(); + void _go_forward(); void _update_drives(); @@ -170,7 +180,7 @@ public: void invalidate(); - void deselect_items(); + void deselect_all(); FileDialog(); ~FileDialog(); diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 53d7ead548..36b383f16c 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,8 +42,6 @@ #endif GradientEdit::GradientEdit() { - grabbed = -1; - grabbing = false; set_focus_mode(FOCUS_ALL); popup = memnew(PopupPanel); @@ -237,7 +235,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { // Snap to "round" coordinates if holding Ctrl. // Be more precise if holding Shift as well if (mm->get_control()) { - newofs = Math::stepify(newofs, mm->get_shift() ? 0.025 : 0.1); + newofs = Math::snapped(newofs, mm->get_shift() ? 0.025 : 0.1); } else if (mm->get_shift()) { // Snap to nearest point if holding just Shift const float snap_threshold = 0.03; diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h index 6e950703bb..eb7367d598 100644 --- a/scene/gui/gradient_edit.h +++ b/scene/gui/gradient_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,8 +44,8 @@ class GradientEdit : public Control { Ref<ImageTexture> checker; - bool grabbing; - int grabbed; + bool grabbing = false; + int grabbed = -1; Vector<Gradient::Point> points; void _draw_checker(int x, int y, int w, int h); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 2bcc1890fe..b93391ee4c 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -154,10 +154,14 @@ Vector2 GraphEditMinimap::_convert_to_graph_position(const Vector2 &p_position) } void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) { + if (!ge->is_minimap_enabled()) { + return; + } + Ref<InputEventMouseButton> mb = p_ev; Ref<InputEventMouseMotion> mm = p_ev; - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { is_pressing = true; @@ -176,7 +180,12 @@ void GraphEditMinimap::_gui_input(const Ref<InputEvent> &p_ev) { accept_event(); } else if (mm.is_valid() && is_pressing) { if (is_resizing) { - ge->set_minimap_size(ge->get_minimap_size() - mm->get_relative()); + // Prevent setting minimap wider than GraphEdit + Vector2 new_minimap_size; + new_minimap_size.x = MIN(get_size().x - mm->get_relative().x, ge->get_size().x - 2.0 * minimap_padding.x); + new_minimap_size.y = MIN(get_size().y - mm->get_relative().y, ge->get_size().y - 2.0 * minimap_padding.y); + ge->set_minimap_size(new_minimap_size); + update(); } else { Vector2 click_position = _convert_to_graph_position(mm->get_position() - minimap_padding) - graph_padding; @@ -276,7 +285,7 @@ void GraphEdit::_update_scroll_offset() { continue; } - Point2 pos = gn->get_offset() * zoom; + Point2 pos = gn->get_position_offset() * zoom; pos -= Point2(h_scroll->get_value(), v_scroll->get_value()); gn->set_position(pos); if (gn->get_scale() != Vector2(zoom, zoom)) { @@ -306,7 +315,7 @@ void GraphEdit::_update_scroll() { } Rect2 r; - r.position = gn->get_offset() * zoom; + r.position = gn->get_position_offset() * zoom; r.size = gn->get_size() * zoom; screen = screen.merge(r); } @@ -337,8 +346,8 @@ void GraphEdit::_update_scroll() { Size2 vmin = v_scroll->get_combined_minimum_size(); // Avoid scrollbar overlapping. - h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, v_scroll->is_visible() ? -vmin.width : 0); - v_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, h_scroll->is_visible() ? -hmin.height : 0); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, v_scroll->is_visible() ? -vmin.width : 0); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, h_scroll->is_visible() ? -hmin.height : 0); set_block_minimum_size_adjust(false); @@ -381,6 +390,15 @@ void GraphEdit::_graph_node_moved(Node *p_gn) { connections_layer->update(); } +void GraphEdit::_graph_node_slot_updated(int p_index, Node *p_gn) { + GraphNode *gn = Object::cast_to<GraphNode>(p_gn); + ERR_FAIL_COND(!gn); + top_layer->update(); + minimap->update(); + update(); + connections_layer->update(); +} + void GraphEdit::add_child_notify(Node *p_child) { Control::add_child_notify(p_child); @@ -389,7 +407,8 @@ void GraphEdit::add_child_notify(Node *p_child) { GraphNode *gn = Object::cast_to<GraphNode>(p_child); if (gn) { gn->set_scale(Vector2(zoom, zoom)); - gn->connect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved), varray(gn)); + gn->connect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved), varray(gn)); + gn->connect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated), varray(gn)); gn->connect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised), varray(gn)); gn->connect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); gn->connect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update)); @@ -401,16 +420,30 @@ void GraphEdit::add_child_notify(Node *p_child) { void GraphEdit::remove_child_notify(Node *p_child) { Control::remove_child_notify(p_child); - if (is_inside_tree()) { + if (p_child == top_layer) { + top_layer = nullptr; + minimap = nullptr; + } else if (p_child == connections_layer) { + connections_layer = nullptr; + } + + if (top_layer != nullptr && is_inside_tree()) { top_layer->call_deferred("raise"); // Top layer always on top! } GraphNode *gn = Object::cast_to<GraphNode>(p_child); if (gn) { - gn->disconnect("offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved)); + gn->disconnect("position_offset_changed", callable_mp(this, &GraphEdit::_graph_node_moved)); + gn->disconnect("slot_updated", callable_mp(this, &GraphEdit::_graph_node_slot_updated)); gn->disconnect("raise_request", callable_mp(this, &GraphEdit::_graph_node_raised)); - gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); - gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update)); + + // In case of the whole GraphEdit being destroyed these references can already be freed. + if (connections_layer != nullptr && connections_layer->is_inside_tree()) { + gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)connections_layer, &CanvasItem::update)); + } + if (minimap != nullptr && minimap->is_inside_tree()) { + gn->disconnect("item_rect_changed", callable_mp((CanvasItem *)minimap, &GraphEditMinimap::update)); + } } } @@ -429,15 +462,15 @@ void GraphEdit::_notification(int p_what) { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - h_scroll->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0); - h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - h_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -hmin.height); - h_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height); + h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - v_scroll->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -vmin.width); - v_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - v_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); - v_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width); + v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); } if (p_what == NOTIFICATION_DRAW) { draw_style_box(get_theme_stylebox("bg"), Rect2(Point2(), get_size())); @@ -502,14 +535,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (is_in_hot_zone(pos, p_point)) { + if (is_in_hot_zone(pos / zoom, p_point / zoom)) { return true; } } for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - if (is_in_hot_zone(pos, p_point)) { + if (is_in_hot_zone(pos / zoom, p_point / zoom)) { return true; } } @@ -520,10 +553,10 @@ bool GraphEdit::_filter_input(const Point2 &p_point) { void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseButton> mb = p_ev; - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) { + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && mb->is_pressed()) { connecting_valid = false; Ref<Texture2D> port = get_theme_icon("port", "GraphNode"); - click_pos = mb->get_position(); + click_pos = mb->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (!gn) { @@ -532,7 +565,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); - if (is_in_hot_zone(pos, click_pos)) { + if (is_in_hot_zone(pos / zoom, click_pos)) { if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) { //check disconnect for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { @@ -574,7 +607,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); - if (is_in_hot_zone(pos, click_pos)) { + if (is_in_hot_zone(pos / zoom, click_pos)) { if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) { //check disconnect for (List<Connection>::Element *E = connections.front(); E; E = E->next()) { @@ -623,11 +656,11 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { connecting_target = false; top_layer->update(); minimap->update(); - connecting_valid = just_disconnected || click_pos.distance_to(connecting_to) > 20.0 * zoom; + connecting_valid = just_disconnected || click_pos.distance_to(connecting_to / zoom) > 20.0 * zoom; if (connecting_valid) { Ref<Texture2D> port = get_theme_icon("port", "GraphNode"); - Vector2 mpos = mm->get_position(); + Vector2 mpos = mm->get_position() / zoom; for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn = Object::cast_to<GraphNode>(get_child(i)); if (!gn) { @@ -638,7 +671,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_output_count(); j++) { Vector2 pos = gn->get_connection_output_position(j) + gn->get_position(); int type = gn->get_connection_output_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -650,7 +683,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { for (int j = 0; j < gn->get_connection_input_count(); j++) { Vector2 pos = gn->get_connection_input_position(j) + gn->get_position(); int type = gn->get_connection_input_type(j); - if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos, mpos)) { + if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && is_in_hot_zone(pos / zoom, mpos)) { connecting_target = true; connecting_to = pos; connecting_target_to = gn->get_name(); @@ -663,7 +696,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { } } - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) { if (connecting_valid) { if (connecting && connecting_target) { String from = connecting_from; @@ -732,6 +765,11 @@ bool GraphEdit::is_in_hot_zone(const Vector2 &pos, const Vector2 &p_mouse_pos) { continue; } Rect2 rect = child->get_rect(); + + // To prevent intersections with other nodes. + rect.position *= zoom; + rect.size *= zoom; + if (rect.has_point(p_mouse_pos)) { //check sub-controls Vector2 subpos = p_mouse_pos - rect.position; @@ -851,9 +889,9 @@ void GraphEdit::_connections_layer_draw() { continue; } - Vector2 frompos = gfrom->get_connection_output_position(E->get().from_port) + gfrom->get_offset() * zoom; + Vector2 frompos = gfrom->get_connection_output_position(E->get().from_port) + gfrom->get_position_offset() * zoom; Color color = gfrom->get_connection_output_color(E->get().from_port); - Vector2 topos = gto->get_connection_input_position(E->get().to_port) + gto->get_offset() * zoom; + Vector2 topos = gto->get_connection_input_position(E->get().to_port) + gto->get_position_offset() * zoom; Color tocolor = gto->get_connection_input_color(E->get().to_port); if (E->get().activity > 0) { @@ -929,7 +967,7 @@ void GraphEdit::_minimap_draw() { continue; } - Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset; + Vector2 node_position = minimap->_convert_from_graph_position(gn->get_position_offset() * zoom - graph_offset) + minimap_offset; Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom); Rect2 node_rect = Rect2(node_position, node_size); @@ -952,7 +990,7 @@ void GraphEdit::_minimap_draw() { continue; } - Vector2 node_position = minimap->_convert_from_graph_position(gn->get_offset() * zoom - graph_offset) + minimap_offset; + Vector2 node_position = minimap->_convert_from_graph_position(gn->get_position_offset() * zoom - graph_offset) + minimap_offset; Vector2 node_size = minimap->_convert_from_graph_position(gn->get_size() * zoom); Rect2 node_rect = Rect2(node_position, node_size); @@ -992,10 +1030,10 @@ void GraphEdit::_minimap_draw() { continue; } - Vector2 from_slot_position = gfrom->get_offset() * zoom + gfrom->get_connection_output_position(E->get().from_port); + Vector2 from_slot_position = gfrom->get_position_offset() * zoom + gfrom->get_connection_output_position(E->get().from_port); Vector2 from_position = minimap->_convert_from_graph_position(from_slot_position - graph_offset) + minimap_offset; Color from_color = gfrom->get_connection_output_color(E->get().from_port); - Vector2 to_slot_position = gto->get_offset() * zoom + gto->get_connection_input_position(E->get().to_port); + Vector2 to_slot_position = gto->get_position_offset() * zoom + gto->get_connection_input_position(E->get().to_port); Vector2 to_position = minimap->_convert_from_graph_position(to_slot_position - graph_offset) + minimap_offset; Color to_color = gto->get_connection_input_color(E->get().to_port); @@ -1029,7 +1067,7 @@ void GraphEdit::set_selected(Node *p_child) { void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseMotion> mm = p_ev; - if (mm.is_valid() && (mm->get_button_mask() & BUTTON_MASK_MIDDLE || (mm->get_button_mask() & BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { + if (mm.is_valid() && (mm->get_button_mask() & MOUSE_BUTTON_MASK_MIDDLE || (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { h_scroll->set_value(h_scroll->get_value() - mm->get_relative().x); v_scroll->set_value(v_scroll->get_value() - mm->get_relative().y); } @@ -1054,7 +1092,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { pos = pos.snapped(Vector2(snap, snap)); } - gn->set_offset(pos); + gn->set_position_offset(pos); } } } @@ -1081,13 +1119,13 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { if (!gn->is_selected() && box_selection_mode_additive) { emit_signal("node_selected", gn); } else if (gn->is_selected() && !box_selection_mode_additive) { - emit_signal("node_unselected", gn); + emit_signal("node_deselected", gn); } gn->set_selected(box_selection_mode_additive); } else { - bool select = (previus_selected.find(gn) != nullptr); + bool select = (previous_selected.find(gn) != nullptr); if (gn->is_selected() && !select) { - emit_signal("node_unselected", gn); + emit_signal("node_deselected", gn); } else if (!gn->is_selected() && select) { emit_signal("node_selected", gn); } @@ -1101,7 +1139,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { Ref<InputEventMouseButton> b = p_ev; if (b.is_valid()) { - if (b->get_button_index() == BUTTON_RIGHT && b->is_pressed()) { + if (b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_pressed()) { if (box_selecting) { box_selecting = false; for (int i = get_child_count() - 1; i >= 0; i--) { @@ -1110,9 +1148,9 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { continue; } - bool select = (previus_selected.find(gn) != nullptr); + bool select = (previous_selected.find(gn) != nullptr); if (gn->is_selected() && !select) { - emit_signal("node_unselected", gn); + emit_signal("node_deselected", gn); } else if (!gn->is_selected() && select) { emit_signal("node_selected", gn); } @@ -1131,7 +1169,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } } - if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && dragging) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && dragging) { if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { //deselect current node for (int i = get_child_count() - 1; i >= 0; i--) { @@ -1141,7 +1179,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { Rect2 r = gn->get_rect(); r.size *= zoom; if (r.has_point(b->get_position())) { - emit_signal("node_unselected", gn); + emit_signal("node_deselected", gn); gn->set_selected(false); } } @@ -1170,7 +1208,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { connections_layer->update(); } - if (b->get_button_index() == BUTTON_LEFT && b->is_pressed()) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT && b->is_pressed()) { GraphNode *gn = nullptr; for (int i = get_child_count() - 1; i >= 0; i--) { @@ -1181,7 +1219,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { continue; } - if (gn_selected->has_point(b->get_position() - gn_selected->get_position())) { + if (gn_selected->has_point((b->get_position() - gn_selected->get_position()) / zoom)) { gn = gn_selected; break; } @@ -1204,7 +1242,7 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { o_gn->set_selected(true); } else { if (o_gn->is_selected()) { - emit_signal("node_unselected", o_gn); + emit_signal("node_deselected", o_gn); } o_gn->set_selected(false); } @@ -1235,36 +1273,36 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { box_selecting_from = b->get_position(); if (b->get_control()) { box_selection_mode_additive = true; - previus_selected.clear(); + previous_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); if (!gn2 || !gn2->is_selected()) { continue; } - previus_selected.push_back(gn2); + previous_selected.push_back(gn2); } } else if (b->get_shift()) { box_selection_mode_additive = false; - previus_selected.clear(); + previous_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); if (!gn2 || !gn2->is_selected()) { continue; } - previus_selected.push_back(gn2); + previous_selected.push_back(gn2); } } else { box_selection_mode_additive = true; - previus_selected.clear(); + previous_selected.clear(); for (int i = get_child_count() - 1; i >= 0; i--) { GraphNode *gn2 = Object::cast_to<GraphNode>(get_child(i)); if (!gn2) { continue; } if (gn2->is_selected()) { - emit_signal("node_unselected", gn2); + emit_signal("node_deselected", gn2); } gn2->set_selected(false); } @@ -1272,55 +1310,40 @@ void GraphEdit::_gui_input(const Ref<InputEvent> &p_ev) { } } - if (b->get_button_index() == BUTTON_LEFT && !b->is_pressed() && box_selecting) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT && !b->is_pressed() && box_selecting) { box_selecting = false; - previus_selected.clear(); + box_selecting_rect = Rect2(); + previous_selected.clear(); top_layer->update(); minimap->update(); } - if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) { - //too difficult to get right - //set_zoom(zoom*ZOOM_SCALE); - } - - if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) { - //too difficult to get right - //set_zoom(zoom/ZOOM_SCALE); - } - if (b->get_button_index() == BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + set_zoom(zoom * ZOOM_SCALE); + } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) { + set_zoom(zoom / ZOOM_SCALE); + } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); - } - if (b->get_button_index() == BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { + } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) { v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); - } - if (b->get_button_index() == BUTTON_WHEEL_RIGHT || (b->get_button_index() == BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { + } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * b->get_factor() / 8); - } - if (b->get_button_index() == BUTTON_WHEEL_LEFT || (b->get_button_index() == BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { + } else if (b->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && Input::get_singleton()->is_key_pressed(KEY_SHIFT))) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * b->get_factor() / 8); } } - Ref<InputEventKey> k = p_ev; - - if (k.is_valid()) { - if (k->get_keycode() == KEY_D && k->is_pressed() && k->get_command()) { + if (p_ev->is_pressed()) { + if (p_ev->is_action("ui_graph_duplicate")) { emit_signal("duplicate_nodes_request"); accept_event(); - } - - if (k->get_keycode() == KEY_C && k->is_pressed() && k->get_command()) { + } else if (p_ev->is_action("ui_copy")) { emit_signal("copy_nodes_request"); accept_event(); - } - - if (k->get_keycode() == KEY_V && k->is_pressed() && k->get_command()) { + } else if (p_ev->is_action("ui_paste")) { emit_signal("paste_nodes_request"); accept_event(); - } - - if (k->get_keycode() == KEY_DELETE && k->is_pressed()) { + } else if (p_ev->is_action("ui_graph_delete")) { emit_signal("delete_nodes_request"); accept_event(); } @@ -1502,10 +1525,10 @@ void GraphEdit::set_minimap_size(Vector2 p_size) { Vector2 minimap_size = minimap->get_size(); // The size might've been adjusted by the minimum size. minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT); - minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_LEFT, -minimap_size.x - MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET); minimap->update(); } @@ -1533,7 +1556,12 @@ bool GraphEdit::is_minimap_enabled() const { } void GraphEdit::_minimap_toggled() { - minimap->update(); + if (is_minimap_enabled()) { + minimap->set_visible(true); + minimap->update(); + } else { + minimap->set_visible(false); + } } void GraphEdit::set_connection_lines_thickness(float p_thickness) { @@ -1576,7 +1604,7 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type); ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type); - ClassDB::bind_method(D_METHOD("set_zoom", "p_zoom"), &GraphEdit::set_zoom); + ClassDB::bind_method(D_METHOD("set_zoom", "zoom"), &GraphEdit::set_zoom); ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom); ClassDB::bind_method(D_METHOD("set_snap", "pixels"), &GraphEdit::set_snap); @@ -1591,9 +1619,9 @@ void GraphEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("set_connection_lines_antialiased", "pixels"), &GraphEdit::set_connection_lines_antialiased); ClassDB::bind_method(D_METHOD("is_connection_lines_antialiased"), &GraphEdit::is_connection_lines_antialiased); - ClassDB::bind_method(D_METHOD("set_minimap_size", "p_size"), &GraphEdit::set_minimap_size); + ClassDB::bind_method(D_METHOD("set_minimap_size", "size"), &GraphEdit::set_minimap_size); ClassDB::bind_method(D_METHOD("get_minimap_size"), &GraphEdit::get_minimap_size); - ClassDB::bind_method(D_METHOD("set_minimap_opacity", "p_opacity"), &GraphEdit::set_minimap_opacity); + ClassDB::bind_method(D_METHOD("set_minimap_opacity", "opacity"), &GraphEdit::set_minimap_opacity); ClassDB::bind_method(D_METHOD("get_minimap_opacity"), &GraphEdit::get_minimap_opacity); ClassDB::bind_method(D_METHOD("set_minimap_enabled", "enable"), &GraphEdit::set_minimap_enabled); @@ -1628,7 +1656,7 @@ void GraphEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("copy_nodes_request")); ADD_SIGNAL(MethodInfo("paste_nodes_request")); ADD_SIGNAL(MethodInfo("node_selected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("node_unselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); + ADD_SIGNAL(MethodInfo("node_deselected", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); 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")); @@ -1640,12 +1668,10 @@ void GraphEdit::_bind_methods() { GraphEdit::GraphEdit() { set_focus_mode(FOCUS_ALL); - awaiting_scroll_offset_update = false; - top_layer = nullptr; top_layer = memnew(GraphEditFilter(this)); add_child(top_layer); top_layer->set_mouse_filter(MOUSE_FILTER_PASS); - top_layer->set_anchors_and_margins_preset(Control::PRESET_WIDE); + top_layer->set_anchors_and_offsets_preset(Control::PRESET_WIDE); top_layer->connect("draw", callable_mp(this, &GraphEdit::_top_layer_draw)); top_layer->connect("gui_input", callable_mp(this, &GraphEdit::_top_layer_input)); @@ -1664,13 +1690,6 @@ GraphEdit::GraphEdit() { v_scroll->set_name("_v_scroll"); top_layer->add_child(v_scroll); - updating = false; - connecting = false; - right_disconnects = false; - - box_selecting = false; - dragging = false; - //set large minmax so it can scroll even if not resized yet h_scroll->set_min(-10000); h_scroll->set_max(10000); @@ -1681,8 +1700,6 @@ GraphEdit::GraphEdit() { h_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &GraphEdit::_scroll_moved)); - zoom = 1; - zoom_hb = memnew(HBoxContainer); top_layer->add_child(zoom_hb); zoom_hb->set_position(Vector2(10, 10)); @@ -1741,17 +1758,15 @@ GraphEdit::GraphEdit() { top_layer->add_child(minimap); minimap->set_name("_minimap"); minimap->set_modulate(Color(1, 1, 1, minimap_opacity)); - minimap->set_mouse_filter(MOUSE_FILTER_STOP); + minimap->set_mouse_filter(MOUSE_FILTER_PASS); minimap->set_custom_minimum_size(Vector2(50, 50)); minimap->set_size(minimap_size); minimap->set_anchors_preset(Control::PRESET_BOTTOM_RIGHT); - minimap->set_margin(Margin::MARGIN_LEFT, -minimap_size.x - MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_TOP, -minimap_size.y - MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_RIGHT, -MINIMAP_OFFSET); - minimap->set_margin(Margin::MARGIN_BOTTOM, -MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_LEFT, -minimap_size.x - MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_TOP, -minimap_size.y - MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_RIGHT, -MINIMAP_OFFSET); + minimap->set_offset(Side::SIDE_BOTTOM, -MINIMAP_OFFSET); minimap->connect("draw", callable_mp(this, &GraphEdit::_minimap_draw)); - setting_scroll_ofs = false; - just_disconnected = false; set_clip_contents(true); } diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h index d081789784..fa3b113705 100644 --- a/scene/gui/graph_edit.h +++ b/scene/gui/graph_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -99,9 +99,9 @@ public: struct Connection { StringName from; StringName to; - int from_port; - int to_port; - float activity; + int from_port = 0; + int to_port = 0; + float activity = 0.0; }; private: @@ -121,41 +121,41 @@ private: HScrollBar *h_scroll; VScrollBar *v_scroll; - float port_grab_distance_horizontal; + float port_grab_distance_horizontal = 0.0; float port_grab_distance_vertical; - bool connecting; + bool connecting = false; String connecting_from; - bool connecting_out; - int connecting_index; - int connecting_type; + bool connecting_out = false; + int connecting_index = 0; + int connecting_type = 0; Color connecting_color; - bool connecting_target; + bool connecting_target = false; Vector2 connecting_to; String connecting_target_to; int connecting_target_index; - bool just_disconnected; - bool connecting_valid; + bool just_disconnected = false; + bool connecting_valid = false; Vector2 click_pos; - bool dragging; - bool just_selected; - bool moving_selection; + bool dragging = false; + bool just_selected = false; + bool moving_selection = false; Vector2 drag_accum; - float zoom; + float zoom = 1.0; - bool box_selecting; - bool box_selection_mode_additive; + bool box_selecting = false; + bool box_selection_mode_additive = false; Point2 box_selecting_from; Point2 box_selecting_to; Rect2 box_selecting_rect; - List<GraphNode *> previus_selected; + List<GraphNode *> previous_selected; - bool setting_scroll_ofs; - bool right_disconnects; - bool updating; - bool awaiting_scroll_offset_update; + bool setting_scroll_ofs = false; + bool right_disconnects = false; + bool updating = false; + bool awaiting_scroll_offset_update = false; List<Connection> connections; float lines_thickness = 2.0f; @@ -167,6 +167,7 @@ private: void _graph_node_raised(Node *p_gn); void _graph_node_moved(Node *p_gn); + void _graph_node_slot_updated(int p_index, Node *p_gn); void _update_scroll(); void _scroll_moved(double); @@ -194,7 +195,7 @@ private: uint32_t type_a; uint32_t type_b; }; - uint64_t key; + uint64_t key = 0; }; bool operator<(const ConnType &p_type) const { diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 4ce33ec8f2..8eba473d57 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,6 +32,12 @@ #include "core/string/translation.h" +struct _MinSizeCache { + int min_size; + bool will_stretch; + int final_size; +}; + bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { String str = p_name; if (str.begins_with("opentype_features/")) { @@ -51,7 +57,7 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } @@ -71,6 +77,8 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { si.enable_left = p_value; } else if (what == "left_type") { si.type_left = p_value; + } else if (what == "left_icon") { + si.custom_slot_left = p_value; } else if (what == "left_color") { si.color_left = p_value; } else if (what == "right_enabled") { @@ -79,11 +87,13 @@ bool GraphNode::_set(const StringName &p_name, const Variant &p_value) { si.type_right = p_value; } else if (what == "right_color") { si.color_right = p_value; + } else if (what == "right_icon") { + si.custom_slot_right = p_value; } else { return false; } - set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right); + set_slot(idx, si.enable_left, si.type_left, si.color_left, si.enable_right, si.type_right, si.color_right, si.custom_slot_left, si.custom_slot_right); update(); return true; } @@ -120,12 +130,16 @@ bool GraphNode::_get(const StringName &p_name, Variant &r_ret) const { r_ret = si.type_left; } else if (what == "left_color") { r_ret = si.color_left; + } else if (what == "left_icon") { + r_ret = si.custom_slot_left; } else if (what == "right_enabled") { r_ret = si.enable_right; } else if (what == "right_type") { r_ret = si.type_right; } else if (what == "right_color") { r_ret = si.color_right; + } else if (what == "right_icon") { + r_ret = si.custom_slot_right; } else { return false; } @@ -152,24 +166,34 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::BOOL, base + "left_enabled")); p_list->push_back(PropertyInfo(Variant::INT, base + "left_type")); p_list->push_back(PropertyInfo(Variant::COLOR, base + "left_color")); + p_list->push_back(PropertyInfo(Variant::OBJECT, base + "left_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); p_list->push_back(PropertyInfo(Variant::BOOL, base + "right_enabled")); p_list->push_back(PropertyInfo(Variant::INT, base + "right_type")); p_list->push_back(PropertyInfo(Variant::COLOR, base + "right_color")); + p_list->push_back(PropertyInfo(Variant::OBJECT, base + "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_STORE_IF_NULL)); idx++; } } void GraphNode::_resort() { - int sep = get_theme_constant("separation"); + /** First pass, determine minimum size AND amount of stretchable elements */ + + Size2i new_size = get_size(); Ref<StyleBox> sb = get_theme_stylebox("frame"); - bool first = true; - Size2 minsize; + int sep = get_theme_constant("separation"); + + bool first = true; + int children_count = 0; + int stretch_min = 0; + int stretch_avail = 0; + float stretch_ratio_total = 0; + Map<Control *, _MinSizeCache> min_size_cache; for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) { + if (!c || !c->is_visible_in_tree()) { continue; } if (c->is_set_as_top_level()) { @@ -177,38 +201,120 @@ void GraphNode::_resort() { } Size2i size = c->get_combined_minimum_size(); + _MinSizeCache msc; - minsize.y += size.y; - minsize.x = MAX(minsize.x, size.x); + stretch_min += size.height; + msc.min_size = size.height; + msc.will_stretch = c->get_v_size_flags() & SIZE_EXPAND; - if (first) { - first = false; - } else { - minsize.y += sep; + if (msc.will_stretch) { + stretch_avail += msc.min_size; + stretch_ratio_total += c->get_stretch_ratio(); } + msc.final_size = msc.min_size; + min_size_cache[c] = msc; + children_count++; } - int vofs = 0; - int w = get_size().x - sb->get_minimum_size().x; + if (children_count == 0) { + return; + } + + int stretch_max = new_size.height - (children_count - 1) * sep; + int stretch_diff = stretch_max - stretch_min; + if (stretch_diff < 0) { + //avoid negative stretch space + stretch_diff = 0; + } + stretch_avail += stretch_diff - sb->get_margin(SIDE_BOTTOM) - sb->get_margin(SIDE_TOP); //available stretch space. + /** Second, pass sucessively to discard elements that can't be stretched, this will run while stretchable + elements exist */ + + while (stretch_ratio_total > 0) { // first of all, don't even be here if no stretchable objects exist + bool refit_successful = true; //assume refit-test will go well + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c || !c->is_visible_in_tree()) { + continue; + } + if (c->is_set_as_top_level()) { + continue; + } + + ERR_FAIL_COND(!min_size_cache.has(c)); + _MinSizeCache &msc = min_size_cache[c]; + + if (msc.will_stretch) { //wants to stretch + //let's see if it can really stretch + + int final_pixel_size = stretch_avail * c->get_stretch_ratio() / stretch_ratio_total; + if (final_pixel_size < msc.min_size) { + //if available stretching area is too small for widget, + //then remove it from stretching area + msc.will_stretch = false; + stretch_ratio_total -= c->get_stretch_ratio(); + refit_successful = false; + stretch_avail -= msc.min_size; + msc.final_size = msc.min_size; + break; + } else { + msc.final_size = final_pixel_size; + } + } + } + + if (refit_successful) { //uf refit went well, break + break; + } + } + + /** Final pass, draw and stretch elements **/ + + int ofs = sb->get_margin(SIDE_TOP); + + first = true; + int idx = 0; cache_y.clear(); + int w = new_size.width - sb->get_minimum_size().x; + for (int i = 0; i < get_child_count(); i++) { Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) { + if (!c || !c->is_visible_in_tree()) { continue; } if (c->is_set_as_top_level()) { continue; } - Size2i size = c->get_combined_minimum_size(); + _MinSizeCache &msc = min_size_cache[c]; - Rect2 r(sb->get_margin(MARGIN_LEFT), sb->get_margin(MARGIN_TOP) + vofs, w, size.y); + if (first) { + first = false; + } else { + ofs += sep; + } + + int from = ofs; + int to = ofs + msc.final_size; + + if (msc.will_stretch && idx == children_count - 1) { + //adjust so the last one always fits perfect + //compensating for numerical imprecision + + to = new_size.height - sb->get_margin(SIDE_BOTTOM); + } + + int size = to - from; + + Rect2 rect(sb->get_margin(SIDE_LEFT), from, w, size); - fit_child_in_rect(c, r); - cache_y.push_back(vofs + size.y * 0.5); + fit_child_in_rect(c, rect); + cache_y.push_back(from - sb->get_margin(SIDE_TOP) + size * 0.5); - vofs += size.y + sep; + ofs = to; + idx++; } update(); @@ -224,7 +330,7 @@ bool GraphNode::has_point(const Point2 &p_point) const { return true; } - if (Rect2(0, 0, get_size().width, comment->get_margin(MARGIN_TOP)).has_point(p_point)) { + if (Rect2(0, 0, get_size().width, comment->get_margin(SIDE_TOP)).has_point(p_point)) { return true; } @@ -261,7 +367,7 @@ void GraphNode::_notification(int p_what) { Color title_color = get_theme_color("title_color"); Point2i icofs = -port->get_size() * 0.5; int edgeofs = get_theme_constant("port_offset"); - icofs.y += sb->get_margin(MARGIN_TOP); + icofs.y += sb->get_margin(SIDE_TOP); draw_style_box(sb, Rect2(Point2(), get_size())); @@ -284,9 +390,9 @@ void GraphNode::_notification(int p_what) { } title_buf->set_width(w); - title_buf->draw(get_canvas_item(), Point2(sb->get_margin(MARGIN_LEFT) + title_h_offset, -title_buf->get_size().y + title_offset), title_color); + title_buf->draw(get_canvas_item(), Point2(sb->get_margin(SIDE_LEFT) + title_h_offset, -title_buf->get_size().y + title_offset), title_color); if (show_close) { - Vector2 cpos = Point2(w + sb->get_margin(MARGIN_LEFT) + close_h_offset, -close->get_height() + close_offset); + Vector2 cpos = Point2(w + sb->get_margin(SIDE_LEFT) + close_h_offset, -close->get_height() + close_offset); draw_texture(close, cpos, close_color); close_rect.position = cpos; close_rect.size = close->get_size(); @@ -355,7 +461,9 @@ void GraphNode::_shape() { void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const Color &p_color_left, bool p_enable_right, int p_type_right, const Color &p_color_right, const Ref<Texture2D> &p_custom_left, const Ref<Texture2D> &p_custom_right) { ERR_FAIL_COND(p_idx < 0); - if (!p_enable_left && p_type_left == 0 && p_color_left == Color(1, 1, 1, 1) && !p_enable_right && p_type_right == 0 && p_color_right == Color(1, 1, 1, 1)) { + if (!p_enable_left && p_type_left == 0 && p_color_left == Color(1, 1, 1, 1) && + !p_enable_right && p_type_right == 0 && p_color_right == Color(1, 1, 1, 1) && + !p_custom_left.is_valid() && !p_custom_right.is_valid()) { slot_info.erase(p_idx); return; } @@ -372,6 +480,8 @@ void GraphNode::set_slot(int p_idx, bool p_enable_left, int p_type_left, const C slot_info[p_idx] = s; update(); connpos_dirty = true; + + emit_signal("slot_updated", p_idx); } void GraphNode::clear_slot(int p_idx) { @@ -472,7 +582,6 @@ void GraphNode::set_title(const String &p_title) { _shape(); update(); - _change_notify("title"); minimum_size_changed(); } @@ -528,14 +637,14 @@ String GraphNode::get_language() const { return language; } -void GraphNode::set_offset(const Vector2 &p_offset) { - offset = p_offset; - emit_signal("offset_changed"); +void GraphNode::set_position_offset(const Vector2 &p_offset) { + position_offset = p_offset; + emit_signal("position_offset_changed"); update(); } -Vector2 GraphNode::get_offset() const { - return offset; +Vector2 GraphNode::get_position_offset() const { + return position_offset; } void GraphNode::set_selected(bool p_selected) { @@ -549,9 +658,9 @@ bool GraphNode::is_selected() { void GraphNode::set_drag(bool p_drag) { if (p_drag) { - drag_from = get_offset(); + drag_from = get_position_offset(); } else { - emit_signal("dragged", drag_from, get_offset()); //useful for undo/redo + emit_signal("dragged", drag_from, get_position_offset()); //useful for undo/redo } } @@ -590,7 +699,7 @@ void GraphNode::_connpos_update() { Size2i size = c->get_combined_minimum_size(); - int y = sb->get_margin(MARGIN_TOP) + vofs; + int y = sb->get_margin(SIDE_TOP) + vofs; int h = size.y; if (slot_info.has(idx)) { @@ -699,7 +808,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) { if (mb.is_valid()) { ERR_FAIL_COND_MSG(get_parent_control() == nullptr, "GraphNode must be the child of a GraphEdit node."); - if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { Vector2 mpos = Vector2(mb->get_position().x, mb->get_position().y); if (close_rect.size != Size2() && close_rect.has_point(mpos)) { //send focus to parent @@ -722,7 +831,7 @@ void GraphNode::_gui_input(const Ref<InputEvent> &p_ev) { emit_signal("raise_request"); } - if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (!mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { resizing = false; } } @@ -787,8 +896,8 @@ void GraphNode::_bind_methods() { ClassDB::bind_method(D_METHOD("get_slot_type_right", "idx"), &GraphNode::get_slot_type_right); ClassDB::bind_method(D_METHOD("get_slot_color_right", "idx"), &GraphNode::get_slot_color_right); - ClassDB::bind_method(D_METHOD("set_offset", "offset"), &GraphNode::set_offset); - ClassDB::bind_method(D_METHOD("get_offset"), &GraphNode::get_offset); + ClassDB::bind_method(D_METHOD("set_position_offset", "offset"), &GraphNode::set_position_offset); + ClassDB::bind_method(D_METHOD("get_position_offset"), &GraphNode::get_position_offset); ClassDB::bind_method(D_METHOD("set_comment", "comment"), &GraphNode::set_comment); ClassDB::bind_method(D_METHOD("is_comment"), &GraphNode::is_comment); @@ -818,14 +927,15 @@ void GraphNode::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position_offset"), "set_position_offset", "get_position_offset"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay"); - ADD_SIGNAL(MethodInfo("offset_changed")); + ADD_SIGNAL(MethodInfo("position_offset_changed")); + ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "idx"))); ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to"))); ADD_SIGNAL(MethodInfo("raise_request")); ADD_SIGNAL(MethodInfo("close_request")); @@ -838,12 +948,5 @@ void GraphNode::_bind_methods() { GraphNode::GraphNode() { title_buf.instance(); - overlay = OVERLAY_DISABLED; - show_close = false; - connpos_dirty = true; set_mouse_filter(MOUSE_FILTER_STOP); - comment = false; - resizable = false; - resizing = false; - selected = false; } diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h index 3cd7ae6e24..1bc54dddb7 100644 --- a/scene/gui/graph_node.h +++ b/scene/gui/graph_node.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,23 +46,14 @@ public: private: struct Slot { - bool enable_left; - int type_left; - Color color_left; - bool enable_right; - int type_right; - Color color_right; + bool enable_left = false; + int type_left = 0; + Color color_left = Color(1, 1, 1, 1); + bool enable_right = false; + int type_right = 0; + Color color_right = Color(1, 1, 1, 1); Ref<Texture2D> custom_slot_left; Ref<Texture2D> custom_slot_right; - - Slot() { - enable_left = false; - type_left = 0; - color_left = Color(1, 1, 1, 1); - enable_right = false; - type_right = 0; - color_right = Color(1, 1, 1, 1); - } }; String title; @@ -72,12 +63,12 @@ private: String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; - bool show_close; - Vector2 offset; - bool comment; - bool resizable; + bool show_close = false; + Vector2 position_offset; + bool comment = false; + bool resizable = false; - bool resizing; + bool resizing = false; Vector2 resizing_from; Vector2 resizing_from_size; @@ -87,7 +78,7 @@ private: struct ConnCache { Vector2 pos; - int type; + int type = 0; Color color; }; @@ -96,16 +87,16 @@ private: Map<int, Slot> slot_info; - bool connpos_dirty; + bool connpos_dirty = true; void _connpos_update(); void _resort(); void _shape(); Vector2 drag_from; - bool selected; + bool selected = false; - Overlay overlay; + Overlay overlay = OVERLAY_DISABLED; protected: void _gui_input(const Ref<InputEvent> &p_ev); @@ -142,8 +133,8 @@ public: void set_language(const String &p_language); String get_language() const; - void set_offset(const Vector2 &p_offset); - Vector2 get_offset() const; + void set_position_offset(const Vector2 &p_offset); + Vector2 get_position_offset() const; void set_selected(bool p_selected); bool is_selected(); diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index a08a348a18..541925a802 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -261,6 +261,4 @@ Size2 GridContainer::get_minimum_size() const { return ms; } -GridContainer::GridContainer() { - columns = 1; -} +GridContainer::GridContainer() {} diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h index 79d4aee284..9b43a5bc7e 100644 --- a/scene/gui/grid_container.h +++ b/scene/gui/grid_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class GridContainer : public Container { GDCLASS(GridContainer, Container); - int columns; + int columns = 1; protected: void _notification(int p_what); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 5be7804ac1..482560d29d 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,7 +50,7 @@ void ItemList::_shape(int p_idx) { } } -void ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bool p_selectable) { +int ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, bool p_selectable) { Item item; item.icon = p_texture; item.icon_transposed = false; @@ -64,14 +64,16 @@ void ItemList::add_item(const String &p_item, const Ref<Texture2D> &p_texture, b item.tooltip_enabled = true; item.custom_bg = Color(0, 0, 0, 0); items.push_back(item); + int item_id = items.size() - 1; _shape(items.size() - 1); update(); shape_changed = true; + return item_id; } -void ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { +int ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { Item item; item.icon = p_item; item.icon_transposed = false; @@ -85,9 +87,11 @@ void ItemList::add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable) { item.tooltip_enabled = true; item.custom_bg = Color(0, 0, 0, 0); items.push_back(item); + int item_id = items.size() - 1; update(); shape_changed = true; + return item_id; } void ItemList::set_item_text(int p_idx, const String &p_text) { @@ -333,7 +337,7 @@ void ItemList::select(int p_idx, bool p_single) { update(); } -void ItemList::unselect(int p_idx) { +void ItemList::deselect(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); if (select_mode != SELECT_MULTI) { @@ -345,7 +349,7 @@ void ItemList::unselect(int p_idx) { update(); } -void ItemList::unselect_all() { +void ItemList::deselect_all() { if (items.size() < 1) { return; } @@ -536,7 +540,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; - if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) { + if (defer_select_single >= 0 && mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_LEFT && !mb->is_pressed()) { select(defer_select_single, true); emit_signal("multi_selected", defer_select_single, true); @@ -544,7 +548,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { return; } - if (mb.is_valid() && (mb->get_button_index() == BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == BUTTON_RIGHT)) && mb->is_pressed()) { + if (mb.is_valid() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (allow_rmb_select && mb->get_button_index() == MOUSE_BUTTON_RIGHT)) && mb->is_pressed()) { search_string = ""; //any mousepress cancels Vector2 pos = mb->get_position(); Ref<StyleBox> bg = get_theme_stylebox("bg"); @@ -573,7 +577,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { int i = closest; if (select_mode == SELECT_MULTI && items[i].selected && mb->get_command()) { - unselect(i); + deselect(i); emit_signal("multi_selected", i, false); } else if (select_mode == SELECT_MULTI && mb->get_shift() && current >= 0 && current < items.size() && current != i) { @@ -590,16 +594,16 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { } } - if (mb->get_button_index() == BUTTON_RIGHT) { + if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", i, get_local_mouse_position()); } } else { - if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == BUTTON_LEFT) { + if (!mb->is_doubleclick() && !mb->get_command() && select_mode == SELECT_MULTI && items[i].selectable && !items[i].disabled && items[i].selected && mb->get_button_index() == MOUSE_BUTTON_LEFT) { defer_select_single = i; return; } - if (items[i].selected && mb->get_button_index() == BUTTON_RIGHT) { + if (items[i].selected && mb->get_button_index() == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", i, get_local_mouse_position()); } else { bool selected = items[i].selected; @@ -614,7 +618,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { } } - if (mb->get_button_index() == BUTTON_RIGHT) { + if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", i, get_local_mouse_position()); } else if (/*select_mode==SELECT_SINGLE &&*/ mb->is_doubleclick()) { emit_signal("item_activated", i); @@ -624,7 +628,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { return; } - if (mb->get_button_index() == BUTTON_RIGHT) { + if (mb->get_button_index() == MOUSE_BUTTON_RIGHT) { emit_signal("rmb_clicked", mb->get_position()); return; @@ -633,10 +637,10 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { // Since closest is null, more likely we clicked on empty space, so send signal to interested controls. Allows, for example, implement items deselecting. emit_signal("nothing_selected"); } - if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) { scroll_bar->set_value(scroll_bar->get_value() - scroll_bar->get_page() * mb->get_factor() / 8); } - if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { + if (mb.is_valid() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) { scroll_bar->set_value(scroll_bar->get_value() + scroll_bar->get_page() * mb->get_factor() / 8); } @@ -759,12 +763,12 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { select(current, false); emit_signal("multi_selected", current, true); } else if (items[current].selected) { - unselect(current); + deselect(current); emit_signal("multi_selected", current, false); } } } else if (p_event->is_action("ui_accept")) { - search_string = ""; //any mousepress cance + search_string = ""; //any mousepress cancels if (current >= 0 && current < items.size()) { emit_signal("item_activated", current); @@ -861,10 +865,10 @@ void ItemList::_notification(int p_what) { Ref<StyleBox> bg = get_theme_stylebox("bg"); int mw = scroll_bar->get_minimum_size().x; - scroll_bar->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -mw); - scroll_bar->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - scroll_bar->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, bg->get_margin(MARGIN_TOP)); - scroll_bar->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, -bg->get_margin(MARGIN_BOTTOM)); + scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -mw); + scroll_bar->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + scroll_bar->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, bg->get_margin(SIDE_TOP)); + scroll_bar->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -bg->get_margin(SIDE_BOTTOM)); Size2 size = get_size(); @@ -879,6 +883,8 @@ void ItemList::_notification(int p_what) { int vseparation = get_theme_constant("vseparation"); int icon_margin = get_theme_constant("icon_margin"); int line_separation = get_theme_constant("line_separation"); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); Ref<StyleBox> sbsel = has_focus() ? get_theme_stylebox("selected_focus") : get_theme_stylebox("selected"); Ref<StyleBox> cursor = has_focus() ? get_theme_stylebox("cursor") : get_theme_stylebox("cursor_unfocused"); @@ -886,7 +892,7 @@ void ItemList::_notification(int p_what) { Color guide_color = get_theme_color("guide_color"); Color font_color = get_theme_color("font_color"); - Color font_color_selected = get_theme_color("font_color_selected"); + Color font_selected_color = get_theme_color("font_selected_color"); if (has_focus()) { RenderingServer::get_singleton()->canvas_item_add_clip_ignore(get_canvas_item(), true); @@ -895,7 +901,7 @@ void ItemList::_notification(int p_what) { } if (shape_changed) { - float max_column_width = 0; + float max_column_width = 0.0; //1- compute item minimum sizes for (int i = 0; i < items.size(); i++) { @@ -1184,13 +1190,12 @@ void ItemList::_notification(int p_what) { max_len = size2.x; } - Color modulate = items[i].selected ? font_color_selected : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); + Color modulate = items[i].selected ? font_selected_color : (items[i].custom_fg != Color() ? items[i].custom_fg : font_color); if (items[i].disabled) { modulate.a *= 0.5; } if (icon_mode == ICON_MODE_TOP && max_text_lines > 0) { - text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; @@ -1201,6 +1206,10 @@ void ItemList::_notification(int p_what) { items.write[i].text_buf->set_width(max_len); items.write[i].text_buf->set_align(HALIGN_CENTER); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + } + items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); } else { if (fixed_column_width > 0) { @@ -1213,7 +1222,6 @@ void ItemList::_notification(int p_what) { text_ofs.y += (items[i].rect_cache.size.height - size2.y) / 2; } - text_ofs = text_ofs.floor(); text_ofs += base_ofs; text_ofs += items[i].rect_cache.position; @@ -1228,6 +1236,11 @@ void ItemList::_notification(int p_what) { } else { items.write[i].text_buf->set_align(HALIGN_LEFT); } + + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(get_canvas_item(), text_ofs, outline_size, font_outline_color); + } + items[i].text_buf->draw(get_canvas_item(), text_ofs, modulate); } } @@ -1270,7 +1283,7 @@ void ItemList::_notification(int p_what) { } const int y = base_ofs.y + separators[i]; - draw_line(Vector2(bg->get_margin(MARGIN_LEFT), y), Vector2(width, y), guide_color); + draw_line(Vector2(bg->get_margin(SIDE_LEFT), y), Vector2(width, y), guide_color); } } } @@ -1314,7 +1327,7 @@ int ItemList::get_item_at_position(const Point2 &p_pos, bool p_exact) const { } bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const { - if (items.empty()) { + if (items.is_empty()) { return true; } @@ -1519,8 +1532,8 @@ void ItemList::_bind_methods() { ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &ItemList::get_item_tooltip); ClassDB::bind_method(D_METHOD("select", "idx", "single"), &ItemList::select, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("unselect", "idx"), &ItemList::unselect); - ClassDB::bind_method(D_METHOD("unselect_all"), &ItemList::unselect_all); + ClassDB::bind_method(D_METHOD("deselect", "idx"), &ItemList::deselect); + ClassDB::bind_method(D_METHOD("deselect_all"), &ItemList::deselect_all); ClassDB::bind_method(D_METHOD("is_selected", "idx"), &ItemList::is_selected); ClassDB::bind_method(D_METHOD("get_selected_items"), &ItemList::get_selected_items); @@ -1613,34 +1626,12 @@ void ItemList::_bind_methods() { } ItemList::ItemList() { - current = -1; - - select_mode = SELECT_SINGLE; - icon_mode = ICON_MODE_LEFT; - - fixed_column_width = 0; - same_column_width = false; - max_text_lines = 1; - max_columns = 1; - auto_height = false; - auto_height_value = 0.0f; - scroll_bar = memnew(VScrollBar); add_child(scroll_bar); - shape_changed = true; scroll_bar->connect("value_changed", callable_mp(this, &ItemList::_scroll_changed)); set_focus_mode(FOCUS_ALL); - current_columns = 1; - search_time_msec = 0; - ensure_selected_visible = false; - defer_select_single = -1; - allow_rmb_select = false; - allow_reselect = false; - do_autoscroll_to_bottom = false; - - icon_scale = 1.0f; set_clip_contents(true); } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 9684ce0a32..86a0174a20 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,7 +52,7 @@ public: private: struct Item { Ref<Texture2D> icon; - bool icon_transposed; + bool icon_transposed = false; Rect2i icon_region; Color icon_modulate; Ref<Texture2D> tag_icon; @@ -62,10 +62,10 @@ private: String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; - bool selectable; - bool selected; - bool disabled; - bool tooltip_enabled; + bool selectable = false; + bool selected = false; + bool disabled = false; + bool tooltip_enabled = false; Variant metadata; String tooltip; Color custom_fg; @@ -79,44 +79,44 @@ private: bool operator<(const Item &p_another) const { return text < p_another.text; } }; - int current; + int current = -1; - bool shape_changed; + bool shape_changed = true; - bool ensure_selected_visible; - bool same_column_width; + bool ensure_selected_visible = false; + bool same_column_width = false; - bool auto_height; - float auto_height_value; + bool auto_height = false; + float auto_height_value = 0.0; Vector<Item> items; Vector<int> separators; - SelectMode select_mode; - IconMode icon_mode; + SelectMode select_mode = SELECT_SINGLE; + IconMode icon_mode = ICON_MODE_LEFT; VScrollBar *scroll_bar; - uint64_t search_time_msec; + uint64_t search_time_msec = 0; String search_string; - int current_columns; - int fixed_column_width; - int max_text_lines; - int max_columns; + int current_columns = 1; + int fixed_column_width = 0; + int max_text_lines = 1; + int max_columns = 1; Size2 fixed_icon_size; Size2 max_item_size_cache; - int defer_select_single; + int defer_select_single = -1; - bool allow_rmb_select; + bool allow_rmb_select = false; - bool allow_reselect; + bool allow_reselect = false; - real_t icon_scale; + real_t icon_scale = 1.0; - bool do_autoscroll_to_bottom; + bool do_autoscroll_to_bottom = false; Array _get_items() const; void _set_items(const Array &p_items); @@ -130,8 +130,8 @@ protected: static void _bind_methods(); public: - void add_item(const String &p_item, const Ref<Texture2D> &p_texture = Ref<Texture2D>(), bool p_selectable = true); - void add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable = true); + int add_item(const String &p_item, const Ref<Texture2D> &p_texture = Ref<Texture2D>(), bool p_selectable = true); + int add_icon_item(const Ref<Texture2D> &p_item, bool p_selectable = true); void set_item_text(int p_idx, const String &p_text); String get_item_text(int p_idx) const; @@ -183,8 +183,8 @@ public: Color get_item_custom_fg_color(int p_idx) const; void select(int p_idx, bool p_single = true); - void unselect(int p_idx); - void unselect_all(); + void deselect(int p_idx); + void deselect_all(); bool is_selected(int p_idx) const; Vector<int> get_selected_items(); bool is_anything_selected(); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 566d77e3fd..be73fd8f51 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -184,17 +184,17 @@ void Label::_notification(int p_what) { Ref<StyleBox> style = get_theme_stylebox("normal"); Ref<Font> font = get_theme_font("font"); Color font_color = get_theme_color("font_color"); - Color font_color_shadow = get_theme_color("font_color_shadow"); + Color font_shadow_color = get_theme_color("font_shadow_color"); Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); int line_spacing = get_theme_constant("line_spacing"); - Color font_outline_modulate = get_theme_color("font_outline_modulate"); + Color font_outline_color = get_theme_color("font_outline_color"); int outline_size = get_theme_constant("outline_size"); int shadow_outline_size = get_theme_constant("shadow_outline_size"); bool rtl = is_layout_rtl(); style->draw(ci, Rect2(Point2(0, 0), get_size())); - float total_h = 0; + float total_h = 0.0; int lines_visible = 0; // Get number of lines to fit to the height. @@ -260,7 +260,8 @@ void Label::_notification(int p_what) { } } } - visible_glyphs = total_glyphs * percent_visible; + + visible_glyphs = MIN(total_glyphs, visible_chars); } Vector2 ofs; @@ -272,7 +273,7 @@ void Label::_notification(int p_what) { case ALIGN_FILL: case ALIGN_LEFT: { if (rtl) { - ofs.x = int(size.width - style->get_margin(MARGIN_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x); + ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x); } else { ofs.x = style->get_offset().x; } @@ -284,7 +285,7 @@ void Label::_notification(int p_what) { if (rtl) { ofs.x = style->get_offset().x; } else { - ofs.x = int(size.width - style->get_margin(MARGIN_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x); + ofs.x = int(size.width - style->get_margin(SIDE_RIGHT) - TS->shaped_text_get_size(lines_rid[i]).x); } } break; } @@ -298,17 +299,17 @@ void Label::_notification(int p_what) { for (int j = 0; j < gl_size; j++) { for (int k = 0; k < glyphs[j].repeat; k++) { if (glyphs[j].font_rid != RID()) { - if (font_color_shadow.a > 0) { - TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + shadow_ofs, glyphs[j].index, font_color_shadow); + if (font_shadow_color.a > 0) { + TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + shadow_ofs, glyphs[j].index, font_shadow_color); if (shadow_outline_size > 0) { //draw shadow - TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, shadow_ofs.y), glyphs[j].index, font_color_shadow); - TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_color_shadow); - TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_color_shadow); + TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, shadow_ofs.y), glyphs[j].index, font_shadow_color); + TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_shadow_color); + TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, shadow_outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off) + Vector2(-shadow_ofs.x, -shadow_ofs.y), glyphs[j].index, font_shadow_color); } } - if (font_outline_modulate.a != 0.0 && outline_size > 0) { - TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_outline_modulate); + if (font_outline_color.a != 0.0 && outline_size > 0) { + TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, outline_size, ofs + Vector2(glyphs[j].x_off, glyphs[j].y_off), glyphs[j].index, font_outline_color); } } ofs.x += glyphs[j].advance; @@ -357,21 +358,25 @@ void Label::_notification(int p_what) { } Size2 Label::get_minimum_size() const { - Size2 min_style = get_theme_stylebox("normal")->get_minimum_size(); - // don't want to mutable everything if (dirty || lines_dirty) { const_cast<Label *>(this)->_shape(); } + Size2 min_size = minsize; + + Ref<Font> font = get_theme_font("font"); + min_size.height = MAX(min_size.height, font->get_height(get_theme_font_size("font_size")) + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM)); + + Size2 min_style = get_theme_stylebox("normal")->get_minimum_size(); if (autowrap) { - return Size2(1, clip ? 1 : minsize.height) + min_style; + return Size2(1, clip ? 1 : min_size.height) + min_style; } else { - Size2 ms = minsize; if (clip) { - ms.width = 1; + min_size.width = 1; } - return ms + min_style; + + return min_size + min_style; } } @@ -391,7 +396,7 @@ int Label::get_visible_line_count() const { Ref<StyleBox> style = get_theme_stylebox("normal"); int line_spacing = get_theme_constant("line_spacing"); int lines_visible = 0; - float total_h = 0; + float total_h = 0.0; for (int64_t i = lines_skipped; i < lines_rid.size(); i++) { total_h += TS->shaped_text_get_size(lines_rid[i]).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM) + line_spacing; if (total_h > (get_size().height - style->get_minimum_size().height + line_spacing)) { @@ -537,8 +542,9 @@ void Label::set_visible_characters(int p_amount) { visible_chars = p_amount; if (get_total_character_count() > 0) { percent_visible = (float)p_amount / (float)get_total_character_count(); + } else { + percent_visible = 1.0; } - _change_notify("percent_visible"); update(); } @@ -555,7 +561,6 @@ void Label::set_percent_visible(float p_percent) { visible_chars = get_total_character_count() * p_percent; percent_visible = p_percent; } - _change_notify("visible_chars"); update(); } @@ -564,6 +569,7 @@ float Label::get_percent_visible() const { } void Label::set_lines_skipped(int p_lines) { + ERR_FAIL_COND(p_lines < 0); lines_skipped = p_lines; _update_visible(); update(); @@ -610,7 +616,7 @@ bool Label::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } diff --git a/scene/gui/label.h b/scene/gui/label.h index 386297f582..032b4112e1 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -72,7 +72,7 @@ private: Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT; Array st_args; - float percent_visible = 1; + float percent_visible = 1.0; int visible_chars = -1; int lines_skipped = 0; diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 9f8b944f4c..d1cd73c803 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -30,6 +30,7 @@ #include "line_edit.h" +#include "core/input/input_map.h" #include "core/object/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -44,6 +45,175 @@ #endif #include "scene/main/window.h" +void LineEdit::_swap_current_input_direction() { + if (input_direction == TEXT_DIRECTION_LTR) { + input_direction = TEXT_DIRECTION_RTL; + } else { + input_direction = TEXT_DIRECTION_LTR; + } + set_cursor_position(get_cursor_position()); + update(); +} + +void LineEdit::_move_cursor_left(bool p_select, bool p_move_by_word) { + if (selection.enabled && !p_select) { + set_cursor_position(selection.begin); + deselect(); + return; + } + + shift_selection_check_pre(p_select); + + if (p_move_by_word) { + int cc = cursor_pos; + + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); + for (int i = words.size() - 1; i >= 0; i--) { + if (words[i].x < cc) { + cc = words[i].x; + break; + } + } + + set_cursor_position(cc); + } else { + if (mid_grapheme_caret_enabled) { + set_cursor_position(get_cursor_position() - 1); + } else { + set_cursor_position(TS->shaped_text_prev_grapheme_pos(text_rid, get_cursor_position())); + } + } + + shift_selection_check_post(p_select); +} + +void LineEdit::_move_cursor_right(bool p_select, bool p_move_by_word) { + if (selection.enabled && !p_select) { + set_cursor_position(selection.end); + deselect(); + return; + } + + shift_selection_check_pre(p_select); + + if (p_move_by_word) { + int cc = cursor_pos; + + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); + for (int i = 0; i < words.size(); i++) { + if (words[i].y > cc) { + cc = words[i].y; + break; + } + } + + set_cursor_position(cc); + } else { + if (mid_grapheme_caret_enabled) { + set_cursor_position(get_cursor_position() + 1); + } else { + set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, get_cursor_position())); + } + } + + shift_selection_check_post(p_select); +} + +void LineEdit::_move_cursor_start(bool p_select) { + shift_selection_check_pre(p_select); + set_cursor_position(0); + shift_selection_check_post(p_select); +} + +void LineEdit::_move_cursor_end(bool p_select) { + shift_selection_check_pre(p_select); + set_cursor_position(text.length()); + shift_selection_check_post(p_select); +} + +void LineEdit::_backspace(bool p_word, bool p_all_to_left) { + if (!editable) { + return; + } + + if (p_all_to_left) { + deselect(); + text = text.substr(0, cursor_pos); + _text_changed(); + return; + } + + if (selection.enabled) { + selection_delete(); + return; + } + + if (p_word) { + int cc = cursor_pos; + + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); + for (int i = words.size() - 1; i >= 0; i--) { + if (words[i].x < cc) { + cc = words[i].x; + } + } + + delete_text(cc, cursor_pos); + + set_cursor_position(cc); + } else { + delete_char(); + } +} + +void LineEdit::_delete(bool p_word, bool p_all_to_right) { + if (!editable) { + return; + } + + if (p_all_to_right) { + deselect(); + text = text.substr(cursor_pos, text.length() - cursor_pos); + _shape(); + set_cursor_position(0); + _text_changed(); + return; + } + + if (selection.enabled) { + selection_delete(); + return; + } + + int text_len = text.length(); + + if (cursor_pos == text_len) { + return; // Nothing to do. + } + + if (p_word) { + int cc = cursor_pos; + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); + for (int i = 0; i < words.size(); i++) { + if (words[i].y > cc) { + cc = words[i].y; + break; + } + } + + delete_text(cursor_pos, cc); + } else { + if (mid_grapheme_caret_enabled) { + set_cursor_position(cursor_pos + 1); + delete_char(); + } else { + int cc = cursor_pos; + set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, cursor_pos)); + delete_text(cc, cursor_pos); + } + } +} + void LineEdit::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseButton> b = p_event; @@ -52,24 +222,24 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { // Ignore mouse clicks in IME input mode. return; } - if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) { menu->set_position(get_screen_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); - //menu->set_scale(get_global_transform().get_scale()); + _generate_context_menu(); menu->popup(); grab_focus(); accept_event(); return; } - if (b->get_button_index() != BUTTON_LEFT) { + if (b->get_button_index() != MOUSE_BUTTON_LEFT) { return; } _reset_caret_blink_timer(); if (b->is_pressed()) { accept_event(); //don't pass event further when clicked on text field - if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { + if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; clear_button_status.pressing_inside = true; update(); @@ -85,11 +255,30 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { selection.creating = true; } else { - if (b->is_doubleclick() && selecting_enabled) { - selection.enabled = true; - selection.begin = 0; - selection.end = text.length(); - selection.doubleclick = true; + if (selecting_enabled) { + if (!b->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) { + // Triple-click select all. + selection.enabled = true; + selection.begin = 0; + selection.end = text.length(); + selection.doubleclick = true; + selection.last_dblclk = 0; + cursor_pos = selection.begin; + } else if (b->is_doubleclick()) { + // Double-click select word. + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); + for (int i = 0; i < words.size(); i++) { + if (words[i].x < cursor_pos && words[i].y > cursor_pos) { + selection.enabled = true; + selection.begin = words[i].x; + selection.end = words[i].y; + selection.doubleclick = true; + selection.last_dblclk = OS::get_singleton()->get_ticks_msec(); + cursor_pos = selection.end; + break; + } + } + } } selection.drag_attempt = false; @@ -106,7 +295,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { update(); } else { - if (!text.empty() && is_editable() && clear_button_enabled) { + if (!text.is_empty() && is_editable() && clear_button_enabled) { bool press_attempt = clear_button_status.press_attempt; clear_button_status.press_attempt = false; if (press_attempt && clear_button_status.pressing_inside && _is_over_clear_button(b->get_position())) { @@ -121,13 +310,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { selection.creating = false; selection.doubleclick = false; - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { - if (selection.enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); - } else { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); - } - } + show_virtual_keyboard(); } update(); @@ -136,7 +319,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - if (!text.empty() && is_editable() && clear_button_enabled) { + if (!text.is_empty() && is_editable() && clear_button_enabled) { bool last_press_inside = clear_button_status.pressing_inside; clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position()); if (last_press_inside != clear_button_status.pressing_inside) { @@ -144,7 +327,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } } - if (m->get_button_mask() & BUTTON_LEFT) { + if (m->get_button_mask() & MOUSE_BUTTON_LEFT) { if (selection.creating) { set_cursor_at_pixel_pos(m->get_position().x); selection_fill_at_cursor(); @@ -159,453 +342,163 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { return; } -#ifdef APPLE_STYLE_KEYS - if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { - uint32_t remap_key = KEY_UNKNOWN; - switch (k->get_keycode()) { - case KEY_F: { - remap_key = KEY_RIGHT; - } break; - case KEY_B: { - remap_key = KEY_LEFT; - } break; - case KEY_P: { - remap_key = KEY_UP; - } break; - case KEY_N: { - remap_key = KEY_DOWN; - } break; - case KEY_D: { - remap_key = KEY_DELETE; - } break; - case KEY_H: { - remap_key = KEY_BACKSPACE; - } break; - case KEY_A: { - remap_key = KEY_HOME; - } break; - case KEY_E: { - remap_key = KEY_END; - } break; + if (context_menu_enabled) { + if (k->is_action("ui_menu", true)) { + Point2 pos = Point2(get_cursor_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2); + menu->set_position(get_global_transform().xform(pos)); + menu->set_size(Vector2(1, 1)); + _generate_context_menu(); + menu->popup(); + menu->grab_focus(); } + } - if (remap_key != KEY_UNKNOWN) { - k->set_keycode(remap_key); - k->set_control(false); + // Default is ENTER, KP_ENTER. Cannot use ui_accept as default includes SPACE + if (k->is_action("ui_text_newline", true)) { + emit_signal("text_entered", text); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { + DisplayServer::get_singleton()->virtual_keyboard_hide(); } } -#endif - - unsigned int code = k->get_keycode(); - - if (k->get_command() && is_shortcut_keys_enabled()) { - bool handled = true; - - switch (code) { - case (KEY_QUOTELEFT): { // Swap current input direction (primary cursor) - - if (input_direction == TEXT_DIRECTION_LTR) { - input_direction = TEXT_DIRECTION_RTL; - } else { - input_direction = TEXT_DIRECTION_LTR; - } - set_cursor_position(get_cursor_position()); - update(); - - } break; - - case (KEY_X): { // CUT. - - if (editable) { - cut_text(); - } - - } break; - - case (KEY_C): { // COPY. - copy_text(); - - } break; - - case (KEY_Y): // PASTE (Yank for unix users). - case (KEY_V): { // PASTE. - - if (editable) { - paste_text(); - } - - } break; - - case (KEY_Z): { // Undo/redo. - if (editable) { - if (k->get_shift()) { - redo(); - } else { - undo(); - } - } - } break; - - case (KEY_U): { // Delete from start to cursor. - - if (editable) { - deselect(); - text = text.substr(cursor_pos, text.length() - cursor_pos); - _shape(); - set_cursor_position(0); - _text_changed(); - } - - } break; - - case (KEY_K): { // Delete from cursor_pos to end. - - if (editable) { - deselect(); - text = text.substr(0, cursor_pos); - _text_changed(); - } + if (is_shortcut_keys_enabled()) { + if (k->is_action("ui_copy", true)) { + copy_text(); + accept_event(); + return; + } - } break; - case (KEY_A): { // Select all. - select(); + if (k->is_action("ui_text_select_all", true)) { + select(); + accept_event(); + return; + } - } break; -#ifdef APPLE_STYLE_KEYS - case (KEY_LEFT): { // Go to start of text - like HOME key. - shift_selection_check_pre(k->get_shift()); - set_cursor_position(0); - shift_selection_check_post(k->get_shift()); - } break; - case (KEY_RIGHT): { // Go to end of text - like END key. - shift_selection_check_pre(k->get_shift()); - set_cursor_position(text.length()); - shift_selection_check_post(k->get_shift()); - } break; - case (KEY_BACKSPACE): { - if (!editable) - break; + // Cut / Paste + if (k->is_action("ui_cut", true)) { + cut_text(); + accept_event(); + return; + } - // If selected, delete the selection - if (selection.enabled) { - selection_delete(); - break; - } + if (k->is_action("ui_paste", true)) { + paste_text(); + accept_event(); + return; + } - // Otherwise delete from cursor to beginning of text edit - int current_pos = get_cursor_position(); - if (current_pos != 0) { - delete_text(0, current_pos); - } - } break; -#endif - default: { - handled = false; - } + // Undo / Redo + if (k->is_action("ui_undo", true)) { + undo(); + accept_event(); + return; } - if (handled) { + if (k->is_action("ui_redo", true)) { + redo(); accept_event(); return; } } - _reset_caret_blink_timer(); - if (!k->get_metakey()) { - bool handled = true; - switch (code) { - case KEY_KP_ENTER: - case KEY_ENTER: { - emit_signal("text_entered", text); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { - DisplayServer::get_singleton()->virtual_keyboard_hide(); - } - - } break; - - case KEY_BACKSPACE: { - if (!editable) { - break; - } - - if (selection.enabled) { - selection_delete(); - break; - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_alt()) { -#else - if (k->get_alt()) { - handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor_pos; - - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = words.size() - 1; i >= 0; i--) { - if (words[i].x < cc) { - cc = words[i].x; - break; - } - } - - delete_text(cc, cursor_pos); - - set_cursor_position(cc); - - } else { - delete_char(); - } - - } break; - case KEY_KP_4: { - if (k->get_unicode() != 0) { - handled = false; - break; - } - [[fallthrough]]; - } - case KEY_LEFT: { -#ifndef APPLE_STYLE_KEYS - if (!k->get_alt()) { -#endif - if (selection.enabled && !k->get_shift()) { - set_cursor_position(selection.begin); - deselect(); - handled = true; - break; - } - - shift_selection_check_pre(k->get_shift()); -#ifndef APPLE_STYLE_KEYS - } -#endif - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - set_cursor_position(0); - } else if (k->get_alt()) { -#else - if (k->get_alt()) { - handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor_pos; - - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = words.size() - 1; i >= 0; i--) { - if (words[i].x < cc) { - cc = words[i].x; - break; - } - } - - set_cursor_position(cc); - - } else { - if (mid_grapheme_caret_enabled) { - set_cursor_position(get_cursor_position() - 1); - } else { - set_cursor_position(TS->shaped_text_prev_grapheme_pos(text_rid, get_cursor_position())); - } - } - - shift_selection_check_post(k->get_shift()); - - } break; - case KEY_KP_6: { - if (k->get_unicode() != 0) { - handled = false; - break; - } - [[fallthrough]]; - } - case KEY_RIGHT: { -#ifndef APPLE_STYLE_KEYS - if (!k->get_alt()) { -#endif - if (selection.enabled && !k->get_shift()) { - set_cursor_position(selection.end); - deselect(); - handled = true; - break; - } - - shift_selection_check_pre(k->get_shift()); -#ifndef APPLE_STYLE_KEYS - } -#endif - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - set_cursor_position(text.length()); - } else if (k->get_alt()) { -#else - if (k->get_alt()) { - handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor_pos; - - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = 0; i < words.size(); i++) { - if (words[i].y > cc) { - cc = words[i].y; - break; - } - } - - set_cursor_position(cc); - - } else { - if (mid_grapheme_caret_enabled) { - set_cursor_position(get_cursor_position() + 1); - } else { - set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, get_cursor_position())); - } - } - - shift_selection_check_post(k->get_shift()); - - } break; - case KEY_UP: { - shift_selection_check_pre(k->get_shift()); - if (get_cursor_position() == 0) { - handled = false; - } - set_cursor_position(0); - shift_selection_check_post(k->get_shift()); - } break; - case KEY_DOWN: { - shift_selection_check_pre(k->get_shift()); - if (get_cursor_position() == text.length()) { - handled = false; - } - set_cursor_position(text.length()); - shift_selection_check_post(k->get_shift()); - } break; - case KEY_DELETE: { - if (!editable) { - break; - } - - if (k->get_shift() && !k->get_command() && !k->get_alt()) { - cut_text(); - break; - } - - if (selection.enabled) { - selection_delete(); - break; - } - - int text_len = text.length(); + // BACKSPACE + if (k->is_action("ui_text_backspace_all_to_left", true)) { + _backspace(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_backspace_word", true)) { + _backspace(true); + accept_event(); + return; + } + if (k->is_action("ui_text_backspace", true)) { + _backspace(); + accept_event(); + return; + } - if (cursor_pos == text_len) { - break; // Nothing to do. - } + // DELETE + if (k->is_action("ui_text_delete_all_to_right", true)) { + _delete(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_delete_word", true)) { + _delete(true); + accept_event(); + return; + } + if (k->is_action("ui_text_delete", true)) { + _delete(); + accept_event(); + return; + } -#ifdef APPLE_STYLE_KEYS - if (k->get_alt()) { -#else - if (k->get_alt()) { - handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor_pos; + // Cursor Movement - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid); - for (int i = 0; i < words.size(); i++) { - if (words[i].y > cc) { - cc = words[i].y; - break; - } - } + k = k->duplicate(); + bool shift_pressed = k->get_shift(); + // Remove shift or else actions will not match. Use above variable for selection. + k->set_shift(false); - delete_text(cursor_pos, cc); + if (k->is_action("ui_text_caret_word_left", true)) { + _move_cursor_left(shift_pressed, true); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_left", true)) { + _move_cursor_left(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_word_right", true)) { + _move_cursor_right(shift_pressed, true); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_right", true)) { + _move_cursor_right(shift_pressed, false); + accept_event(); + return; + } - } else { - if (mid_grapheme_caret_enabled) { - set_cursor_position(cursor_pos + 1); - delete_char(); - } else { - int cc = cursor_pos; - set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, cursor_pos)); - delete_text(cc, cursor_pos); - } - } + // Up = Home, Down = End + if (k->is_action("ui_text_caret_up", true) || k->is_action("ui_text_caret_line_start", true) || k->is_action("ui_text_caret_page_up", true)) { + _move_cursor_start(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_down", true) || k->is_action("ui_text_caret_line_end", true) || k->is_action("ui_text_caret_page_down", true)) { + _move_cursor_end(shift_pressed); + accept_event(); + return; + } - } break; - case KEY_KP_7: { - if (k->get_unicode() != 0) { - handled = false; - break; - } - [[fallthrough]]; - } - case KEY_HOME: { - shift_selection_check_pre(k->get_shift()); - set_cursor_position(0); - shift_selection_check_post(k->get_shift()); - } break; - case KEY_KP_1: { - if (k->get_unicode() != 0) { - handled = false; - break; - } - [[fallthrough]]; - } - case KEY_END: { - shift_selection_check_pre(k->get_shift()); - set_cursor_position(text.length()); - shift_selection_check_post(k->get_shift()); - } break; - case KEY_MENU: { - if (context_menu_enabled) { - Point2 pos = Point2(get_cursor_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2); - menu->set_position(get_global_transform().xform(pos)); - menu->set_size(Vector2(1, 1)); - //menu->set_scale(get_global_transform().get_scale()); - menu->popup(); - menu->grab_focus(); - } - } break; + // Misc + if (k->is_action("ui_swap_input_direction", true)) { + _swap_current_input_direction(); + accept_event(); + return; + } - default: { - handled = false; - } break; - } + _reset_caret_blink_timer(); - if (handled) { - accept_event(); - } 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(); - char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 }; - int prev_len = text.length(); - append_at_cursor(ucodestr); - if (text.length() != prev_len) { - _text_changed(); - } - accept_event(); - } + // Allow unicode handling if: + // * No Modifiers are pressed (except shift) + bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey()); - } else { - return; - } + if (allow_unicode_handling && editable && k->get_unicode() >= 32) { + // Handle Unicode (if no modifiers active) + selection_delete(); + char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 }; + int prev_len = text.length(); + append_at_cursor(ucodestr); + if (text.length() != prev_len) { + _text_changed(); } - - update(); + accept_event(); } - - return; } } @@ -635,10 +528,17 @@ Variant LineEdit::get_drag_data(const Point2 &p_point) { } bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const { + bool drop_override = Control::can_drop_data(p_point, p_data); // In case user wants to drop custom data. + if (drop_override) { + return drop_override; + } + return p_data.get_type() == Variant::STRING; } void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { + Control::drop_data(p_point, p_data); + if (p_data.get_type() == Variant::STRING) { set_cursor_at_pixel_pos(p_point.x); int selected = selection.end - selection.begin; @@ -653,7 +553,7 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { } Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const { - if (!text.empty() && is_editable() && _is_over_clear_button(p_pos)) { + if (!text.is_empty() && is_editable() && _is_over_clear_button(p_pos)) { return CURSOR_ARROW; } return Control::get_cursor_shape(p_pos); @@ -735,7 +635,7 @@ void LineEdit::_notification(int p_what) { } int x_ofs = 0; - bool using_placeholder = text.empty() && ime_text.empty(); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); float text_width = TS->shaped_text_get_size(text_rid).x; float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM); @@ -743,7 +643,7 @@ void LineEdit::_notification(int p_what) { case ALIGN_FILL: case ALIGN_LEFT: { if (rtl) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width))); } else { x_ofs = style->get_offset().x; } @@ -752,26 +652,26 @@ void LineEdit::_notification(int p_what) { if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (text_width)) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - (text_width)) / 2); } } break; case ALIGN_RIGHT: { if (rtl) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width))); } } break; } - int ofs_max = width - style->get_margin(MARGIN_RIGHT); + int ofs_max = width - style->get_margin(SIDE_RIGHT); int y_area = height - style->get_minimum_size().height; int y_ofs = style->get_offset().y + (y_area - text_height) / 2; Color selection_color = get_theme_color("selection_color"); - Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_color_uneditable"); - Color font_color_selected = get_theme_color("font_color_selected"); + Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_uneditable_color"); + Color font_selected_color = get_theme_color("font_selected_color"); Color cursor_color = get_theme_color("cursor_color"); // Draw placeholder color. @@ -791,14 +691,14 @@ 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); + r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); if (align == ALIGN_CENTER) { if (scroll_offset == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); } ofs_max -= r_icon->get_width(); @@ -834,14 +734,32 @@ void LineEdit::_notification(int p_what) { // Draw text. ofs.y += TS->shaped_text_get_ascent(text_rid); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); + if (outline_size > 0 && font_outline_color.a > 0) { + Vector2 oofs = ofs; + for (int i = 0; i < gl_size; i++) { + for (int j = 0; j < glyphs[i].repeat; j++) { + if (ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) { + if (glyphs[i].font_rid != RID()) { + TS->font_draw_glyph_outline(glyphs[i].font_rid, ci, glyphs[i].font_size, outline_size, oofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color); + } + } + oofs.x += glyphs[i].advance; + } + if (oofs.x >= ofs_max) { + break; + } + } + } for (int i = 0; i < gl_size; i++) { bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end; for (int j = 0; j < glyphs[i].repeat; j++) { if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) { if (glyphs[i].font_rid != RID()) { - TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color); + TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color); } else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { - TS->draw_hex_code_box(ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color); + TS->draw_hex_code_box(ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color); } } ofs.x += glyphs[i].advance; @@ -891,7 +809,7 @@ void LineEdit::_notification(int p_what) { } } else { { - // IME intermidiet text range. + // IME intermediate text range. Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos, cursor_pos + ime_text.length()); for (int i = 0; i < sel.size(); i++) { Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height); @@ -930,7 +848,7 @@ void LineEdit::_notification(int p_what) { } if (has_focus()) { - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + TS->shaped_text_get_size(text_rid).y), get_viewport()->get_window_id()); } @@ -947,27 +865,20 @@ void LineEdit::_notification(int p_what) { } } - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height; 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) && virtual_keyboard_enabled) { - if (selection.enabled) { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); - } else { - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); - } - } - + show_virtual_keyboard(); } break; case NOTIFICATION_FOCUS_EXIT: { if (caret_blink_enabled && !caret_force_displayed) { caret_blink_timer->stop(); } - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); } @@ -1001,13 +912,17 @@ void LineEdit::copy_text() { } void LineEdit::cut_text() { - if (selection.enabled && !pass) { + if (editable && selection.enabled && !pass) { DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin)); selection_delete(); } } void LineEdit::paste_text() { + if (!editable) { + return; + } + // Strip escape characters like \n and \t as they can't be displayed on LineEdit. String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes(); @@ -1028,6 +943,10 @@ void LineEdit::paste_text() { } void LineEdit::undo() { + if (!editable) { + return; + } + if (undo_stack_pos == nullptr) { if (undo_stack.size() <= 1) { return; @@ -1047,6 +966,10 @@ void LineEdit::undo() { } void LineEdit::redo() { + if (!editable) { + return; + } + if (undo_stack_pos == nullptr) { return; } @@ -1088,7 +1011,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { case ALIGN_FILL: case ALIGN_LEFT: { if (rtl) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } else { x_ofs = style->get_offset().x; } @@ -1097,28 +1020,28 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); } } break; case ALIGN_RIGHT: { if (rtl) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } } break; } - bool using_placeholder = text.empty() && ime_text.empty(); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; if (align == ALIGN_CENTER) { if (scroll_offset == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); } } @@ -1136,7 +1059,7 @@ Vector2i LineEdit::get_cursor_pixel_pos() { case ALIGN_FILL: case ALIGN_LEFT: { if (rtl) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } else { x_ofs = style->get_offset().x; } @@ -1145,28 +1068,28 @@ Vector2i LineEdit::get_cursor_pixel_pos() { if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); } } break; case ALIGN_RIGHT: { if (rtl) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } } break; } - bool using_placeholder = text.empty() && ime_text.empty(); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; if (align == ALIGN_CENTER) { if (scroll_offset == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); } } @@ -1231,6 +1154,8 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) { } draw_caret = true; + + notify_property_list_changed(); } bool LineEdit::cursor_get_force_displayed() const { @@ -1407,6 +1332,21 @@ Array LineEdit::get_structured_text_bidi_override_options() const { void LineEdit::clear() { clear_internal(); _text_changed(); + + // This should reset virtual keyboard state if needed. + if (has_focus()) { + show_virtual_keyboard(); + } +} + +void LineEdit::show_virtual_keyboard() { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { + if (selection.enabled) { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); + } else { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); + } + } } String LineEdit::get_text() const { @@ -1460,7 +1400,7 @@ void LineEdit::set_cursor_position(int p_pos) { case ALIGN_FILL: case ALIGN_LEFT: { if (rtl) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } else { x_ofs = style->get_offset().x; } @@ -1469,34 +1409,34 @@ void LineEdit::set_cursor_position(int p_pos) { if (scroll_offset != 0) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); } } break; case ALIGN_RIGHT: { if (rtl) { x_ofs = style->get_offset().x; } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width))); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); } } break; } - int ofs_max = get_size().width - style->get_margin(MARGIN_RIGHT); - bool using_placeholder = text.empty() && ime_text.empty(); + int ofs_max = get_size().width - style->get_margin(SIDE_RIGHT); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; if (align == ALIGN_CENTER) { if (scroll_offset == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); } ofs_max -= r_icon->get_width(); } - // Note: Use too coordinates to fit IME input range. + // Note: Use two coordinates to fit IME input range. Vector2i primary_catret_offset = get_cursor_pixel_pos(); if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) { @@ -1559,18 +1499,18 @@ Size2 LineEdit::get_minimum_size() const { Size2 min_size; // Minimum size of text. - int space_size = font->get_char_size('m', 0, font_size).x; - min_size.width = get_theme_constant("minimum_spaces") * space_size; + int em_space_size = font->get_char_size('M', 0, font_size).x; + min_size.width = get_theme_constant("minimum_character_width") * em_space_size; if (expand_to_text_length) { // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end. - min_size.width = MAX(min_size.width, full_width + space_size); + min_size.width = MAX(min_size.width, full_width + em_space_size); } min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size)); // Take icons into account. - bool using_placeholder = text.empty() && ime_text.empty(); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; @@ -1949,7 +1889,6 @@ void LineEdit::_text_changed() { void LineEdit::_emit_text_change() { emit_signal("text_changed", text); - _change_notify("text"); text_changed_dirty = false; } @@ -1994,8 +1933,8 @@ void LineEdit::_shape() { void LineEdit::_fit_to_width() { if (align == ALIGN_FILL) { Ref<StyleBox> style = get_theme_stylebox("normal"); - int t_width = get_size().width - style->get_margin(MARGIN_RIGHT) - style->get_margin(MARGIN_LEFT); - bool using_placeholder = text.empty() && ime_text.empty(); + int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT); + bool using_placeholder = text.is_empty() && ime_text.is_empty(); bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon; @@ -2034,25 +1973,50 @@ void LineEdit::_create_undo_state() { undo_stack.push_back(op); } +int LineEdit::_get_menu_action_accelerator(const String &p_action) { + const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action); + if (!events) { + return 0; + } + + // Use first event in the list for the accelerator. + const List<Ref<InputEvent>>::Element *first_event = events->front(); + if (!first_event) { + return 0; + } + + const Ref<InputEventKey> event = first_event->get(); + if (event.is_null()) { + return 0; + } + + // Use physical keycode if non-zero + if (event->get_physical_keycode() != 0) { + return event->get_physical_keycode_with_modifiers(); + } else { + return event->get_keycode_with_modifiers(); + } +} + void LineEdit::_generate_context_menu() { // Reorganize context menu. menu->clear(); if (editable) { - menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0); + menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0); } - menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0); + menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : 0); if (editable) { - menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0); + menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : 0); } menu->add_separator(); if (is_selecting_enabled()) { - menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0); + menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : 0); } if (editable) { menu->add_item(RTR("Clear"), MENU_CLEAR); menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0); - menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0); + menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_undo") : 0); + menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_redo") : 0); } menu->add_separator(); menu->add_submenu_item(RTR("Text writing direction"), "DirMenu"); @@ -2082,7 +2046,7 @@ bool LineEdit::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } @@ -2113,6 +2077,12 @@ void LineEdit::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); } +void LineEdit::_validate_property(PropertyInfo &property) const { + if (!caret_blink_enabled && property.name == "caret_blink_speed") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed); @@ -2255,9 +2225,6 @@ LineEdit::LineEdit() { text_rid = TS->create_shaped_text(); _create_undo_state(); - clear_button_status.press_attempt = false; - clear_button_status.pressing_inside = false; - deselect(); set_focus_mode(FOCUS_ALL); set_default_cursor_shape(CURSOR_IBEAM); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index e7b2a34eed..ef36377f2e 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -94,7 +94,7 @@ private: Point2 ime_selection; RID text_rid; - float full_width = 0; + float full_width = 0.0; bool selecting_enabled = true; @@ -129,19 +129,20 @@ private: Ref<Texture2D> right_icon; struct Selection { - int begin; - int end; - int cursor_start; - bool enabled; - bool creating; - bool doubleclick; - bool drag_attempt; + int begin = 0; + int end = 0; + int cursor_start = 0; + bool enabled = false; + bool creating = false; + bool doubleclick = false; + bool drag_attempt = false; + uint64_t last_dblclk = 0; } selection; struct TextOperation { - int cursor_pos; - int scroll_offset; - int cached_width; + int cursor_pos = 0; + int scroll_offset = 0; + int cached_width = 0; String text; }; List<TextOperation> undo_stack; @@ -163,6 +164,7 @@ private: void _clear_redo(); void _create_undo_state(); + int _get_menu_action_accelerator(const String &p_action); void _generate_context_menu(); void _shape(); @@ -188,15 +190,23 @@ private: void _editor_settings_changed(); - void _gui_input(Ref<InputEvent> p_event); - void _notification(int p_what); + void _swap_current_input_direction(); + void _move_cursor_left(bool p_select, bool p_move_by_word = false); + void _move_cursor_right(bool p_select, bool p_move_by_word = false); + void _move_cursor_start(bool p_select); + void _move_cursor_end(bool p_select); + void _backspace(bool p_word = false, bool p_all_to_left = false); + void _delete(bool p_word = false, bool p_all_to_right = false); protected: + void _notification(int p_what); static void _bind_methods(); + void _gui_input(Ref<InputEvent> p_event); bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + void _validate_property(PropertyInfo &property) const override; public: void set_align(Align p_align); @@ -306,6 +316,9 @@ public: Ref<Texture2D> get_right_icon(); virtual bool is_text_field() const override; + + void show_virtual_keyboard(); + LineEdit(); ~LineEdit(); }; diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp index b66ee514dc..1f7b61e3d1 100644 --- a/scene/gui/link_button.cpp +++ b/scene/gui/link_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -163,8 +163,8 @@ void LinkButton::_notification(int p_what) { } break; case DRAW_HOVER_PRESSED: case DRAW_PRESSED: { - if (has_theme_color("font_color_pressed")) { - color = get_theme_color("font_color_pressed"); + if (has_theme_color("font_pressed_color")) { + color = get_theme_color("font_pressed_color"); } else { color = get_theme_color("font_color"); } @@ -173,12 +173,12 @@ void LinkButton::_notification(int p_what) { } break; case DRAW_HOVER: { - color = get_theme_color("font_color_hover"); + color = get_theme_color("font_hover_color"); do_underline = underline_mode != UNDERLINE_MODE_NEVER; } break; case DRAW_DISABLED: { - color = get_theme_color("font_color_disabled"); + color = get_theme_color("font_disabled_color"); do_underline = underline_mode == UNDERLINE_MODE_ALWAYS; } break; @@ -191,9 +191,17 @@ void LinkButton::_notification(int p_what) { int width = text_buf->get_line_width(); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); if (is_layout_rtl()) { + if (outline_size > 0 && font_outline_color.a > 0) { + text_buf->draw_outline(get_canvas_item(), Vector2(size.width - width, 0), outline_size, font_outline_color); + } text_buf->draw(get_canvas_item(), Vector2(size.width - width, 0), color); } else { + if (outline_size > 0 && font_outline_color.a > 0) { + text_buf->draw_outline(get_canvas_item(), Vector2(0, 0), outline_size, font_outline_color); + } text_buf->draw(get_canvas_item(), Vector2(0, 0), color); } @@ -231,7 +239,7 @@ bool LinkButton::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } @@ -294,7 +302,6 @@ void LinkButton::_bind_methods() { LinkButton::LinkButton() { text_buf.instance(); - underline_mode = UNDERLINE_MODE_ALWAYS; set_focus_mode(FOCUS_NONE); set_default_cursor_shape(CURSOR_POINTING_HAND); } diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h index 8c1daef166..7eaa9f88b6 100644 --- a/scene/gui/link_button.h +++ b/scene/gui/link_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -48,7 +48,7 @@ public: private: String text; Ref<TextLine> text_buf; - UnderlineMode underline_mode; + UnderlineMode underline_mode = UNDERLINE_MODE_ALWAYS; Dictionary opentype_features; String language; diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp index b674b492d8..0e9610d0a3 100644 --- a/scene/gui/margin_container.cpp +++ b/scene/gui/margin_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h index 12e230d9d7..b782976ada 100644 --- a/scene/gui/margin_container.h +++ b/scene/gui/margin_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index b98b3f7094..5acc7e808a 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -118,7 +118,6 @@ void MenuButton::set_disable_shortcuts(bool p_disabled) { } MenuButton::MenuButton() { - switch_on_hover = false; set_flat(true); set_toggle_mode(true); set_disable_shortcuts(false); diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h index 65b46d5b69..fd9ae6021e 100644 --- a/scene/gui/menu_button.h +++ b/scene/gui/menu_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,9 +37,9 @@ class MenuButton : public Button { GDCLASS(MenuButton, Button); - bool clicked; - bool switch_on_hover; - bool disable_shortcuts; + bool clicked = false; + bool switch_on_hover = false; + bool disable_shortcuts = false; PopupMenu *popup; Array _get_items() const; diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp index bc71ae94f5..29a38ad5e3 100644 --- a/scene/gui/nine_patch_rect.cpp +++ b/scene/gui/nine_patch_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,12 +44,12 @@ void NinePatchRect::_notification(int p_what) { texture->get_rect_region(rect, src_rect, rect, src_rect); RID ci = get_canvas_item(); - RS::get_singleton()->canvas_item_add_nine_patch(ci, 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); + RS::get_singleton()->canvas_item_add_nine_patch(ci, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center); } } Size2 NinePatchRect::get_minimum_size() const { - return Size2(margin[MARGIN_LEFT] + margin[MARGIN_RIGHT], margin[MARGIN_TOP] + margin[MARGIN_BOTTOM]); + return Size2(margin[SIDE_LEFT] + margin[SIDE_RIGHT], margin[SIDE_TOP] + margin[SIDE_BOTTOM]); } void NinePatchRect::_bind_methods() { @@ -73,10 +73,10 @@ void NinePatchRect::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_GROUP("Patch Margin", "patch_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "patch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_patch_margin", "get_patch_margin", SIDE_BOTTOM); ADD_GROUP("Axis Stretch", "axis_stretch_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode"); @@ -98,37 +98,22 @@ void NinePatchRect::set_texture(const Ref<Texture2D> &p_tex) { */ minimum_size_changed(); emit_signal("texture_changed"); - _change_notify("texture"); } Ref<Texture2D> NinePatchRect::get_texture() const { return texture; } -void NinePatchRect::set_patch_margin(Margin p_margin, int p_size) { - ERR_FAIL_INDEX((int)p_margin, 4); - margin[p_margin] = p_size; +void NinePatchRect::set_patch_margin(Side p_side, int p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + margin[p_side] = p_size; update(); minimum_size_changed(); - switch (p_margin) { - case MARGIN_LEFT: - _change_notify("patch_margin_left"); - break; - case MARGIN_TOP: - _change_notify("patch_margin_top"); - break; - case MARGIN_RIGHT: - _change_notify("patch_margin_right"); - break; - case MARGIN_BOTTOM: - _change_notify("patch_margin_bottom"); - break; - } } -int NinePatchRect::get_patch_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return margin[p_margin]; +int NinePatchRect::get_patch_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return margin[p_side]; } void NinePatchRect::set_region_rect(const Rect2 &p_region_rect) { @@ -139,7 +124,6 @@ void NinePatchRect::set_region_rect(const Rect2 &p_region_rect) { region_rect = p_region_rect; item_rect_changed(); - _change_notify("region_rect"); } Rect2 NinePatchRect::get_region_rect() const { @@ -174,16 +158,7 @@ NinePatchRect::AxisStretchMode NinePatchRect::get_v_axis_stretch_mode() const { } NinePatchRect::NinePatchRect() { - margin[MARGIN_LEFT] = 0; - margin[MARGIN_RIGHT] = 0; - margin[MARGIN_BOTTOM] = 0; - margin[MARGIN_TOP] = 0; - set_mouse_filter(MOUSE_FILTER_IGNORE); - draw_center = true; - - axis_h = AXIS_STRETCH_MODE_STRETCH; - axis_v = AXIS_STRETCH_MODE_STRETCH; } NinePatchRect::~NinePatchRect() { diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h index a539ad43c0..f9a3f31fe5 100644 --- a/scene/gui/nine_patch_rect.h +++ b/scene/gui/nine_patch_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,12 +43,13 @@ public: AXIS_STRETCH_MODE_TILE_FIT, }; - bool draw_center; - int margin[4]; + bool draw_center = true; + int margin[4] = {}; Rect2 region_rect; Ref<Texture2D> texture; - AxisStretchMode axis_h, axis_v; + AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH; + AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH; protected: void _notification(int p_what); @@ -59,8 +60,8 @@ public: void set_texture(const Ref<Texture2D> &p_tex); Ref<Texture2D> get_texture() const; - void set_patch_margin(Margin p_margin, int p_size); - int get_patch_margin(Margin p_margin) const; + void set_patch_margin(Side p_side, int p_size); + int get_patch_margin(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index 902d2715d4..e52b6917be 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -62,13 +62,13 @@ void OptionButton::_notification(int p_what) { if (get_theme_constant("modulate_arrow")) { switch (get_draw_mode()) { case DRAW_PRESSED: - clr = get_theme_color("font_color_pressed"); + clr = get_theme_color("font_pressed_color"); break; case DRAW_HOVER: - clr = get_theme_color("font_color_hover"); + clr = get_theme_color("font_hover_color"); break; case DRAW_DISABLED: - clr = get_theme_color("font_color_disabled"); + clr = get_theme_color("font_disabled_color"); break; default: clr = get_theme_color("font_color"); @@ -90,11 +90,11 @@ void OptionButton::_notification(int p_what) { case NOTIFICATION_THEME_CHANGED: { if (has_theme_icon("arrow")) { if (is_layout_rtl()) { - _set_internal_margin(MARGIN_LEFT, Control::get_theme_icon("arrow")->get_width()); - _set_internal_margin(MARGIN_RIGHT, 0.f); + _set_internal_margin(SIDE_LEFT, Control::get_theme_icon("arrow")->get_width()); + _set_internal_margin(SIDE_RIGHT, 0.f); } else { - _set_internal_margin(MARGIN_LEFT, 0.f); - _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width()); + _set_internal_margin(SIDE_LEFT, 0.f); + _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon("arrow")->get_width()); } } } break; @@ -336,16 +336,15 @@ void OptionButton::_bind_methods() { } OptionButton::OptionButton() { - current = -1; set_toggle_mode(true); set_text_align(ALIGN_LEFT); if (is_layout_rtl()) { if (has_theme_icon("arrow")) { - _set_internal_margin(MARGIN_LEFT, Control::get_theme_icon("arrow")->get_width()); + _set_internal_margin(SIDE_LEFT, Control::get_theme_icon("arrow")->get_width()); } } else { if (has_theme_icon("arrow")) { - _set_internal_margin(MARGIN_RIGHT, Control::get_theme_icon("arrow")->get_width()); + _set_internal_margin(SIDE_RIGHT, Control::get_theme_icon("arrow")->get_width()); } } set_action_mode(ACTION_MODE_BUTTON_PRESS); diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h index fec7695969..d846e395ad 100644 --- a/scene/gui/option_button.h +++ b/scene/gui/option_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,7 +38,7 @@ class OptionButton : public Button { GDCLASS(OptionButton, Button); PopupMenu *popup; - int current; + int current = -1; void _focused(int p_which); void _selected(int p_which); diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp index 28cc056d6e..995e985c3a 100644 --- a/scene/gui/panel.cpp +++ b/scene/gui/panel.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/panel.h b/scene/gui/panel.h index e2c1ddc91d..84fd6aaead 100644 --- a/scene/gui/panel.h +++ b/scene/gui/panel.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 051b4de825..11d822c5e1 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h index 92743f2c47..f27ca7fad7 100644 --- a/scene/gui/panel_container.h +++ b/scene/gui/panel_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 791c78e2b4..36bcca61a7 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/popup.h b/scene/gui/popup.h index 48e7ea9452..0355405d7c 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 07f03ad40e..bfbd46a9f0 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,8 +52,8 @@ Size2 PopupMenu::_get_contents_minimum_size() const { 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 - float max_w = 0; - float icon_w = 0; + float max_w = 0.0; + float icon_w = 0.0; int check_w = MAX(get_theme_icon("checked")->get_width(), get_theme_icon("radio_checked")->get_width()) + hseparation; int accel_max_w = 0; bool has_check = false; @@ -62,7 +62,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { Size2 size; Size2 icon_size = items[i].get_icon_size(); - size.height = MAX(icon_size.height, items[i].text_buf->get_size().y); + size.height = _get_item_height(i); icon_w = MAX(icon_size.width, icon_w); size.width += items[i].h_ofs; @@ -72,9 +72,7 @@ Size2 PopupMenu::_get_contents_minimum_size() const { } size.width += items[i].text_buf->get_size().x; - if (i > 0) { - size.height += vseparation; - } + size.height += vseparation; if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { int accel_w = hseparation * 2; @@ -91,7 +89,9 @@ Size2 PopupMenu::_get_contents_minimum_size() const { minsize.height += size.height; } - minsize.width += max_w + icon_w + accel_max_w; + int item_side_padding = get_theme_constant("item_start_padding") + get_theme_constant("item_end_padding"); + minsize.width += max_w + icon_w + accel_max_w + item_side_padding; + if (has_check) { minsize.width += check_w; } @@ -106,13 +106,35 @@ Size2 PopupMenu::_get_contents_minimum_size() const { return minsize; } +int PopupMenu::_get_item_height(int p_item) const { + ERR_FAIL_INDEX_V(p_item, items.size(), 0); + ERR_FAIL_COND_V(p_item < 0, 0); + + int icon_height = items[p_item].get_icon_size().height; + if (items[p_item].checkable_type) { + icon_height = MAX(icon_height, MAX(get_theme_icon("checked")->get_height(), get_theme_icon("radio_checked")->get_height())); + } + + int text_height = items[p_item].text_buf->get_size().height; + if (text_height == 0 && !items[p_item].separator) { + text_height = get_theme_font("font")->get_height(get_theme_font_size("font_size")); + } + + int separator_height = 0; + if (items[p_item].separator) { + separator_height = MAX(get_theme_stylebox("separator")->get_minimum_size().height, MAX(get_theme_stylebox("labeled_separator_left")->get_minimum_size().height, get_theme_stylebox("labeled_separator_right")->get_minimum_size().height)); + } + + return MAX(separator_height, MAX(text_height, icon_height)); +} + int PopupMenu::_get_items_total_height() const { 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, items[i].text_buf->get_size().y) + vsep; + items_total_height += _get_item_height(i) + vsep; } // Subtract a separator which is not needed for the last item. @@ -152,11 +174,9 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const { } for (int i = 0; i < items.size(); i++) { - if (i > 0) { - ofs.y += vseparation; - } + ofs.y += i > 0 ? vseparation : (float)vseparation / 2; - ofs.y += MAX(items[i].get_icon_size().height, items[i].text_buf->get_size().y); + ofs.y += _get_item_height(i); if (p_over.y - control->get_position().y < ofs.y) { return i; @@ -202,7 +222,7 @@ void PopupMenu::_activate_submenu(int p_over) { 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->set_as_minsize(); // Shrink the popup size to its contents. submenu_popup->popup(); // Set autohide areas @@ -339,7 +359,7 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) { 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)))) { + if (button_idx == MOUSE_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; @@ -455,6 +475,10 @@ void PopupMenu::_draw_items() { 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"); + // Space between the item content and the sides of popup menu. + int item_start_padding = get_theme_constant("item_start_padding"); + int item_end_padding = get_theme_constant("item_end_padding"); + bool rtl = control->is_layout_rtl(); Ref<StyleBox> style = get_theme_stylebox("panel"); Ref<StyleBox> hover = get_theme_stylebox("hover"); @@ -475,10 +499,10 @@ void PopupMenu::_draw_items() { int vseparation = get_theme_constant("vseparation"); int hseparation = get_theme_constant("hseparation"); Color font_color = get_theme_color("font_color"); - Color font_color_disabled = get_theme_color("font_color_disabled"); - Color font_color_accel = get_theme_color("font_color_accel"); - Color font_color_hover = get_theme_color("font_color_hover"); - Color font_color_separator = get_theme_color("font_color_separator"); + Color font_disabled_color = get_theme_color("font_disabled_color"); + Color font_accelerator_color = get_theme_color("font_accelerator_color"); + Color font_hover_color = get_theme_color("font_hover_color"); + Color font_separator_color = get_theme_color("font_separator_color"); 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; @@ -506,22 +530,20 @@ void PopupMenu::_draw_items() { // 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; - } + // For the first item only add half a separation. For all other items, add a whole separation to the offset. + ofs.y += i > 0 ? vseparation : (float)vseparation / 2; _shape_item(i); Point2 item_ofs = ofs; Size2 icon_size = items[i].get_icon_size(); - float h = MAX(icon_size.height, items[i].text_buf->get_size().y); + float h = _get_item_height(i); if (i == mouse_over) { if (rtl) { - hover->draw(ci, Rect2(item_ofs + Point2(-hseparation + scroll_width, -vseparation / 2), Size2(display_width + hseparation * 2, h + vseparation))); + hover->draw(ci, Rect2(item_ofs + Point2(scroll_width, -vseparation / 2), Size2(display_width, h + vseparation))); } else { - hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(display_width + hseparation * 2, h + vseparation))); + hover->draw(ci, Rect2(item_ofs + Point2(0, -vseparation / 2), Size2(display_width, h + vseparation))); } } @@ -531,24 +553,28 @@ void PopupMenu::_draw_items() { item_ofs.x += items[i].h_ofs; if (items[i].separator) { int sep_h = separator->get_center_size().height + separator->get_minimum_size().height; + int sep_ofs = Math::floor((h - sep_h) / 2.0); if (text != String()) { int text_size = items[i].text_buf->get_size().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))); + labeled_separator_left->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(MAX(0, text_left - item_ofs.x), 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))); + labeled_separator_right->draw(ci, Rect2(Point2(text_right, item_ofs.y + sep_ofs), 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(display_width, sep_h))); + separator->draw(ci, Rect2(item_ofs + Point2(0, sep_ofs), Size2(display_width, sep_h))); } } Color icon_color(1, 1, 1, items[i].disabled ? 0.5 : 1); + // For non-separator items, add some padding for the content. + item_ofs.x += item_start_padding; + // Checkboxes if (items[i].checkable_type) { Texture2D *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr(); @@ -571,35 +597,53 @@ void PopupMenu::_draw_items() { // Submenu arrow on right hand side if (items[i].submenu != "") { if (rtl) { - submenu->draw(ci, Point2(scroll_width + style->get_margin(MARGIN_LEFT), item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); + submenu->draw(ci, Point2(scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); } else { - submenu->draw(ci, Point2(display_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 - style->get_margin(SIDE_RIGHT) - submenu->get_width() - item_end_padding, item_ofs.y + Math::floor(h - submenu->get_height()) / 2), icon_color); } } // Text + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); if (items[i].separator) { if (text != String()) { int center = (display_width - items[i].text_buf->get_size().width) / 2; - items[i].text_buf->draw(ci, Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), font_color_separator); + Vector2 text_pos = Point2(center, item_ofs.y + Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + items[i].text_buf->draw(ci, text_pos, font_separator_color); } } else { item_ofs.x += icon_ofs + check_ofs; if (rtl) { - items[i].text_buf->draw(ci, Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); + Vector2 text_pos = Size2(control->get_size().width - items[i].text_buf->get_size().width - item_ofs.x, item_ofs.y) + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color)); } else { - items[i].text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), items[i].disabled ? font_color_disabled : (i == mouse_over ? font_color_hover : font_color)); + Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + items[i].text_buf->draw(ci, text_pos, items[i].disabled ? font_disabled_color : (i == mouse_over ? font_hover_color : font_color)); } } // Accelerator / Shortcut if (items[i].accel || (items[i].shortcut.is_valid() && items[i].shortcut->is_valid())) { if (rtl) { - item_ofs.x = scroll_width + style->get_margin(MARGIN_LEFT); + item_ofs.x = scroll_width + style->get_margin(SIDE_LEFT) + item_end_padding; } else { - item_ofs.x = display_width - style->get_margin(MARGIN_RIGHT) - items[i].accel_text_buf->get_size().x; + item_ofs.x = display_width - style->get_margin(SIDE_RIGHT) - items[i].accel_text_buf->get_size().x - item_end_padding; } - items[i].accel_text_buf->draw(ci, item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)), i == mouse_over ? font_color_hover : font_color_accel); + Vector2 text_pos = item_ofs + Point2(0, Math::floor((h - items[i].text_buf->get_size().y) / 2.0)); + if (outline_size > 0 && font_outline_color.a > 0) { + items[i].accel_text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + items[i].accel_text_buf->draw(ci, text_pos, i == mouse_over ? font_hover_color : font_accelerator_color); } // Cache the item vertical offset from the first item and the height @@ -678,6 +722,7 @@ void PopupMenu::_notification(int p_what) { for (int i = 0; i < items.size(); i++) { items.write[i].xl_text = tr(items[i].text); items.write[i].dirty = true; + _shape_item(i); } child_controls_changed(); @@ -745,10 +790,10 @@ void PopupMenu::_notification(int p_what) { // 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)); + margin_container->add_theme_constant_override("margin_top", panel_style->get_margin(Side::SIDE_TOP)); + margin_container->add_theme_constant_override("margin_bottom", panel_style->get_margin(Side::SIDE_BOTTOM)); + margin_container->add_theme_constant_override("margin_left", panel_style->get_margin(Side::SIDE_LEFT)); + margin_container->add_theme_constant_override("margin_right", panel_style->get_margin(Side::SIDE_RIGHT)); } } break; } @@ -1349,10 +1394,10 @@ void PopupMenu::remove_item(int p_idx) { child_controls_changed(); } -void PopupMenu::add_separator(const String &p_text) { +void PopupMenu::add_separator(const String &p_text, int p_id) { Item sep; sep.separator = true; - sep.id = -1; + sep.id = p_id; if (p_text != String()) { sep.text = p_text; sep.xl_text = tr(p_text); @@ -1600,7 +1645,7 @@ void PopupMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_item", "idx"), &PopupMenu::remove_item); - ClassDB::bind_method(D_METHOD("add_separator", "label"), &PopupMenu::add_separator, DEFVAL(String())); + ClassDB::bind_method(D_METHOD("add_separator", "label", "id"), &PopupMenu::add_separator, DEFVAL(String()), DEFVAL(-1)); ClassDB::bind_method(D_METHOD("clear"), &PopupMenu::clear); ClassDB::bind_method(D_METHOD("_set_items"), &PopupMenu::_set_items); @@ -1636,14 +1681,13 @@ void PopupMenu::_bind_methods() { void PopupMenu::popup(const Rect2 &p_bounds) { moved = Vector2(); 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); + margin_container->set_anchors_and_offsets_preset(Control::PRESET_WIDE); add_child(margin_container); margin_container->connect("draw", callable_mp(this, &PopupMenu::_draw_background)); @@ -1655,7 +1699,7 @@ PopupMenu::PopupMenu() { // The control which will display the items control = memnew(Control); control->set_clip_contents(false); - control->set_anchors_and_margins_preset(Control::PRESET_WIDE); + control->set_anchors_and_offsets_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); @@ -1663,19 +1707,6 @@ PopupMenu::PopupMenu() { connect("window_input", callable_mp(this, &PopupMenu::_gui_input)); - mouse_over = -1; - submenu_over = -1; - initial_button_mask = 0; - during_grabbed_click = false; - - allow_search = true; - search_time_msec = 0; - search_string = ""; - - set_hide_on_item_selection(true); - set_hide_on_checkable_item_selection(true); - set_hide_on_multistate_item_selection(false); - submenu_timer = memnew(Timer); submenu_timer->set_wait_time(0.3); submenu_timer->set_one_shot(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index a082fcf0e7..e4cbe984c9 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,28 +51,28 @@ class PopupMenu : public Popup { String language; Control::TextDirection text_direction = Control::TEXT_DIRECTION_AUTO; - bool checked; + bool checked = false; enum { CHECKABLE_TYPE_NONE, CHECKABLE_TYPE_CHECK_BOX, CHECKABLE_TYPE_RADIO_BUTTON, } checkable_type; - int max_states; - int state; - bool separator; - bool disabled; - bool dirty; - int id; + int max_states = 0; + int state = 0; + bool separator = false; + bool disabled = false; + bool dirty = true; + int id = 0; Variant metadata; String submenu; String tooltip; - uint32_t accel; - int _ofs_cache; - int _height_cache; - int h_ofs; + uint32_t accel = 0; + int _ofs_cache = 0; + int _height_cache = 0; + int h_ofs = 0; Ref<Shortcut> shortcut; - bool shortcut_is_global; - bool shortcut_is_disabled; + bool shortcut_is_global = false; + bool shortcut_is_disabled = false; // Returns (0,0) if icon is null. Size2 get_icon_size() const { @@ -82,19 +82,7 @@ class PopupMenu : public Popup { Item() { text_buf.instance(); accel_text_buf.instance(); - dirty = true; - checked = false; checkable_type = CHECKABLE_TYPE_NONE; - separator = false; - max_states = 0; - state = 0; - accel = 0; - disabled = false; - _ofs_cache = 0; - _height_cache = 0; - h_ofs = 0; - shortcut_is_global = false; - shortcut_is_disabled = false; } }; @@ -104,15 +92,16 @@ class PopupMenu : public Popup { Timer *submenu_timer; List<Rect2> autohide_areas; Vector<Item> items; - int initial_button_mask; - bool during_grabbed_click; - int mouse_over; - int submenu_over; + int initial_button_mask = 0; + bool during_grabbed_click = false; + int mouse_over = -1; + int submenu_over = -1; Rect2 parent_rect; String _get_accel_text(const Item &p_item) const; int _get_mouse_over(const Point2 &p_over) const; virtual Size2 _get_contents_minimum_size() const override; + int _get_item_height(int p_item) const; int _get_items_total_height() const; void _scroll_to_item(int p_item); @@ -123,9 +112,9 @@ class PopupMenu : public Popup { void _submenu_timeout(); uint64_t popup_time_msec = 0; - bool hide_on_item_selection; - bool hide_on_checkable_item_selection; - bool hide_on_multistate_item_selection; + bool hide_on_item_selection = true; + bool hide_on_checkable_item_selection = true; + bool hide_on_multistate_item_selection = false; Vector2 moved; Array _get_items() const; @@ -136,9 +125,9 @@ class PopupMenu : public Popup { 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; + bool allow_search = true; + uint64_t search_time_msec = 0; + String search_string = ""; MarginContainer *margin_container; ScrollContainer *scroll_container; @@ -228,7 +217,7 @@ public: void remove_item(int p_idx); - void add_separator(const String &p_text = String()); + void add_separator(const String &p_text = String(), int p_id = -1); void clear(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index c111ddff58..6e8dfd5994 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -74,7 +74,13 @@ void ProgressBar::_notification(int p_what) { if (percent_visible) { String txt = TS->format_number(itos(int(get_as_ratio() * 100))) + TS->percent_sign(); TextLine tl = TextLine(txt, font, font_size); - tl.draw(get_canvas_item(), (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(), font_color); + Vector2 text_pos = (Point2(get_size().width - tl.get_size().x, get_size().height - tl.get_size().y) / 2).round(); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); + if (outline_size > 0 && font_outline_color.a > 0) { + tl.draw_outline(get_canvas_item(), text_pos, outline_size, font_outline_color); + } + tl.draw(get_canvas_item(), text_pos, font_color); } } } @@ -98,5 +104,4 @@ void ProgressBar::_bind_methods() { ProgressBar::ProgressBar() { set_v_size_flags(0); set_step(0.01); - percent_visible = true; } diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h index f00f993adf..fb6060d932 100644 --- a/scene/gui/progress_bar.h +++ b/scene/gui/progress_bar.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class ProgressBar : public Range { GDCLASS(ProgressBar, Range); - bool percent_visible; + bool percent_visible = true; protected: void _notification(int p_what); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index bdb9f408f0..86b775e795 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -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.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("If \"Exp Edit\" is enabled, \"Min Value\" must be greater than 0."); @@ -47,7 +47,6 @@ void Range::_value_changed_notify() { _value_changed(shared->val); emit_signal("value_changed", shared->val); update(); - _change_notify("value"); } void Range::Shared::emit_value_changed() { @@ -63,7 +62,6 @@ void Range::Shared::emit_value_changed() { void Range::_changed_notify(const char *p_what) { emit_signal("changed"); update(); - _change_notify(p_what); } void Range::Shared::emit_changed(const char *p_what) { @@ -171,7 +169,10 @@ void Range::set_as_ratio(double p_value) { } double Range::get_as_ratio() const { - ERR_FAIL_COND_V_MSG(Math::is_equal_approx(get_max(), get_min()), 0.0, "Cannot get ratio when minimum and maximum value are equal."); + if (Math::is_equal_approx(get_max(), get_min())) { + // Avoid division by zero. + return 1.0; + } if (shared->exp_ratio && get_min() >= 0) { double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2); @@ -311,17 +312,7 @@ bool Range::is_lesser_allowed() const { Range::Range() { shared = memnew(Shared); - shared->min = 0; - shared->max = 100; - shared->val = 0; - shared->step = 1; - shared->page = 0; shared->owners.insert(this); - shared->exp_ratio = false; - shared->allow_greater = false; - shared->allow_lesser = false; - - _rounded_values = false; } Range::~Range() { diff --git a/scene/gui/range.h b/scene/gui/range.h index 9ba367aaa4..1072a109c6 100644 --- a/scene/gui/range.h +++ b/scene/gui/range.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,11 +37,14 @@ class Range : public Control { GDCLASS(Range, Control); struct Shared { - double val, min, max; - double step, page; - bool exp_ratio; - bool allow_greater; - bool allow_lesser; + double val = 0.0; + double min = 0.0; + double max = 100.0; + double step = 1.0; + double page = 0.0; + bool exp_ratio = false; + bool allow_greater = false; + bool allow_lesser = false; Set<Range *> owners; void emit_value_changed(); void emit_changed(const char *p_what = ""); @@ -62,7 +65,7 @@ protected: static void _bind_methods(); - bool _rounded_values; + bool _rounded_values = false; public: void set_value(double p_val); diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp index 773acb2713..6d7f2cfd57 100644 --- a/scene/gui/reference_rect.cpp +++ b/scene/gui/reference_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h index becbbf47c5..7097e83a15 100644 --- a/scene/gui/reference_rect.h +++ b/scene/gui/reference_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/rich_text_effect.cpp b/scene/gui/rich_text_effect.cpp index 5b201f45d3..39718a269a 100644 --- a/scene/gui/rich_text_effect.cpp +++ b/scene/gui/rich_text_effect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/rich_text_effect.h b/scene/gui/rich_text_effect.h index 1aa62c1c83..f2e2823eff 100644 --- a/scene/gui/rich_text_effect.h +++ b/scene/gui/rich_text_effect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 8fd9dc7ddb..09f6578295 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -45,7 +45,7 @@ #include "editor/editor_scale.h" #endif -RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) { +RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) const { if (p_free) { if (p_item->subitems.size()) { return p_item->subitems.front()->get(); @@ -90,7 +90,7 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) { return nullptr; } -RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) { +RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) const { if (p_free) { if (p_item->subitems.size()) { return p_item->subitems.back()->get(); @@ -220,7 +220,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> if (tab_size > 0) { // Align inline tabs. Vector<float> tabs; - tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width); + tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width); l.text_buf->tab_align(tabs); } @@ -314,7 +314,7 @@ void RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> table->rows.clear(); Vector2 offset; - float row_height = 0; + float row_height = 0.0; for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. @@ -392,7 +392,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> if (tab_size > 0) { // Align inline tabs. Vector<float> tabs; - tabs.push_back(tab_size * p_base_font->get_char_size('m', 0, p_base_font_size).width); + tabs.push_back(tab_size * p_base_font->get_char_size(' ', 0, p_base_font_size).width); l.text_buf->tab_align(tabs); } @@ -404,6 +404,18 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> break; } switch (it->type) { + case ITEM_DROPCAP: { + // Add dropcap. + const ItemDropcap *dc = (ItemDropcap *)it; + if (dc != nullptr) { + l.text_buf->set_dropcap(dc->text, dc->font, dc->font_size, dc->dropcap_margins); + l.dc_color = dc->color; + l.dc_ol_size = dc->ol_size; + l.dc_ol_color = dc->ol_color; + } else { + l.text_buf->clear_dropcap(); + } + } break; case ITEM_NEWLINE: { Ref<Font> font = _find_font(it); if (font.is_null()) { @@ -442,6 +454,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> ItemImage *img = (ItemImage *)it; l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1); text += String::chr(0xfffc); + l.char_count += 1; } break; case ITEM_TABLE: { ItemTable *table = static_cast<ItemTable *>(it); @@ -541,7 +554,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> table->rows.clear(); Vector2 offset; - float row_height = 0; + float row_height = 0.0; for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) { ERR_CONTINUE(E->get()->type != ITEM_FRAME); // Children should all be frames. @@ -575,7 +588,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> offset.x += table->columns[column].width + hseparation + frame->padding.size.x; row_height = MAX(yofs, row_height); - if (column == col_count - 1) { + // Add row height after last column of the row or last cell of the table. + if (column == col_count - 1 || E->next() == nullptr) { offset.x = 0; row_height += vseparation; table->total_height += row_height; @@ -606,11 +620,11 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> } } -void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) { +int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, bool p_shadow_as_outline, const Point2 &p_shadow_ofs) { Vector2 off; - ERR_FAIL_COND(p_frame == nullptr); - ERR_FAIL_COND(p_line < 0 || p_line >= p_frame->lines.size()); + ERR_FAIL_COND_V(p_frame == nullptr, 0); + ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), 0); Line &l = p_frame->lines.write[p_line]; @@ -619,7 +633,7 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ Variant meta; if (it_from == nullptr) { - return; + return 0; } RID ci = get_canvas_item(); @@ -679,14 +693,32 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ } } + // Draw dropcap. + int dc_lines = l.text_buf->get_dropcap_lines(); + float h_off = l.text_buf->get_dropcap_size().x; + if (l.dc_ol_size > 0) { + l.text_buf->draw_dropcap_outline(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_ol_size, l.dc_ol_color); + } + l.text_buf->draw_dropcap(ci, p_ofs + ((rtl) ? Vector2() : Vector2(l.offset.x, 0)), l.dc_color); + + int line_count = 0; + Size2 ctrl_size = get_size(); // Draw text. for (int line = 0; line < l.text_buf->get_line_count(); line++) { RID rid = l.text_buf->get_line_rid(line); + if (p_ofs.y + off.y >= ctrl_size.height) { + break; + } + if (p_ofs.y + off.y + TS->shaped_text_get_size(rid).y <= 0) { + off.y += TS->shaped_text_get_size(rid).y; + continue; + } float width = l.text_buf->get_width(); float length = TS->shaped_text_get_width(rid); // Draw line. + line_count++; if (rtl) { off.x = p_width - l.offset.x - width; @@ -718,9 +750,17 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ } break; } + if (line <= dc_lines) { + if (rtl) { + off.x -= h_off; + } else { + off.x += h_off; + } + } + //draw_rect(Rect2(p_ofs + off, TS->shaped_text_get_size(rid)), Color(1,0,0), false, 2); //DEBUG_RECTS - off.y += TS->shaped_text_get_ascent(rid); + off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top(); // Draw inlined objects. Array objects = TS->shaped_text_get_objects(rid); for (int i = 0; i < objects.size(); i++) { @@ -738,6 +778,7 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ Color odd_row_bg = get_theme_color("table_odd_row_bg"); Color even_row_bg = get_theme_color("table_even_row_bg"); Color border = get_theme_color("table_border"); + int hseparation = get_theme_constant("table_hseparation"); int col_count = table->columns.size(); int row_count = table->rows.size(); @@ -754,15 +795,15 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ coff.x = rect.size.width - table->columns[col].width - coff.x; } if (row % 2 == 0) { - draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true); + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->odd_row_bg != Color(0, 0, 0, 0) ? frame->odd_row_bg : odd_row_bg), true); } else { - draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true); + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->even_row_bg != Color(0, 0, 0, 0) ? frame->even_row_bg : even_row_bg), true); } - draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false); + draw_rect(Rect2(p_ofs + rect.position + off + coff - frame->padding.position, Size2(table->columns[col].width + hseparation + frame->padding.position.x + frame->padding.size.x, table->rows[row])), (frame->border != Color(0, 0, 0, 0) ? frame->border : border), false); } for (int j = 0; j < frame->lines.size(); j++) { - _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_color_shadow, p_shadow_as_outline, p_shadow_ofs); + _draw_line(frame, j, p_ofs + rect.position + off + Vector2(0, frame->lines[j].offset.y), rect.size.x, p_base_color, p_outline_size, p_outline_color, p_font_shadow_color, p_shadow_as_outline, p_shadow_ofs); } idx++; } @@ -781,8 +822,8 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ // Draw oulines and shadow. for (int i = 0; i < gl_size; i++) { Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start); - int size = _find_outline_size(it); - Color font_color = _find_outline_color(it, Color(0, 0, 0, 0)); + int size = _find_outline_size(it, p_outline_size); + Color font_color = _find_outline_color(it, p_outline_color); if (size <= 0) { gloff.x += glyphs[i].advance; continue; @@ -882,9 +923,9 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ if (visible) { if (frid != RID()) { if (p_shadow_as_outline) { - TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, shadow_ofs.y), gl, p_font_color_shadow); - TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow); - TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, -shadow_ofs.y), gl, p_font_color_shadow); + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, shadow_ofs.y), gl, p_font_shadow_color); + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(shadow_ofs.x, -shadow_ofs.y), gl, p_font_shadow_color); + TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff + Vector2(-shadow_ofs.x, -shadow_ofs.y), gl, p_font_shadow_color); } TS->font_draw_glyph_outline(frid, ci, glyphs[i].font_size, size, p_ofs + fx_offset + gloff, gl, font_color); } @@ -894,7 +935,7 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ } // Draw main text. - Color selection_fg = get_theme_color("font_color_selected"); + Color selection_fg = get_theme_color("font_selected_color"); Color selection_bg = get_theme_color("selection_color"); int sel_start = -1; @@ -1038,8 +1079,10 @@ void RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ off.x += glyphs[i].advance; } } - off.y += TS->shaped_text_get_descent(rid); + off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom(); } + + return line_count; } void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame, int *r_click_line, Item **r_click_item, int *r_click_char, bool *r_outside) { @@ -1075,7 +1118,8 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); while (ofs.y < size.height && from_line < main->lines.size()) { - ofs.y += _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); + _find_click_in_line(p_frame, from_line, ofs, text_rect.size.x, p_click, r_click_frame, r_click_line, r_click_item, r_click_char); + ofs.y += main->lines[from_line].text_buf->get_size().y; if (((r_click_item != nullptr) && ((*r_click_item) != nullptr)) || ((r_click_frame != nullptr) && ((*r_click_frame) != nullptr))) { if (r_outside != nullptr) { *r_outside = false; @@ -1130,7 +1174,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V } break; } - off.y += TS->shaped_text_get_ascent(rid); + off.y += TS->shaped_text_get_ascent(rid) + l.text_buf->get_spacing_top(); Array objects = TS->shaped_text_get_objects(rid); for (int i = 0; i < objects.size(); i++) { @@ -1194,7 +1238,7 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (rect.has_point(p_click) && !table_hit) { char_pos = TS->shaped_text_hit_test_position(rid, p_click.x - rect.position.x); } - off.y += TS->shaped_text_get_descent(rid); + off.y += TS->shaped_text_get_descent(rid) + l.text_buf->get_spacing_bottom(); } if (char_pos >= 0) { @@ -1202,8 +1246,19 @@ float RichTextLabel::_find_click_in_line(ItemFrame *p_frame, int p_line, const V if (r_click_item != nullptr) { Item *it = p_frame->lines[p_line].from; Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr; - it = _get_item_at_pos(it, it_to, char_pos); - *r_click_item = it; + if (char_pos == p_frame->lines[p_line].char_count) { + // Selection after the end of line, select last item. + if (it_to != nullptr) { + *r_click_item = _get_prev_item(it_to); + } else { + for (Item *i = it; i && i != it_to; i = _get_next_item(i)) { + *r_click_item = i; + } + } + } else { + // Selection in the line. + *r_click_item = _get_item_at_pos(it, it_to, char_pos); + } } if (r_click_frame != nullptr) { @@ -1248,7 +1303,7 @@ void RichTextLabel::_update_scroll() { scroll_visible = true; scroll_w = vscroll->get_combined_minimum_size().width; vscroll->show(); - vscroll->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -scroll_w); + vscroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -scroll_w); } else { scroll_visible = false; scroll_w = 0; @@ -1358,19 +1413,20 @@ void RichTextLabel::_notification(int p_what) { } Ref<Font> base_font = get_theme_font("normal_font"); Color base_color = get_theme_color("default_color"); - Color outline_color = get_theme_color("outline_color"); + Color outline_color = get_theme_color("font_outline_color"); int outline_size = get_theme_constant("outline_size"); - Color font_color_shadow = get_theme_color("font_color_shadow"); + Color font_shadow_color = get_theme_color("font_shadow_color"); bool use_outline = get_theme_constant("shadow_as_outline"); Point2 shadow_ofs(get_theme_constant("shadow_offset_x"), get_theme_constant("shadow_offset_y")); + visible_paragraph_count = 0; visible_line_count = 0; // New cache draw. Point2 ofs = text_rect.get_position() + Vector2(0, main->lines[from_line].offset.y - vofs); while (ofs.y < size.height && from_line < main->lines.size()) { - visible_line_count++; - _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_color_shadow, use_outline, shadow_ofs); + visible_paragraph_count++; + visible_line_count += _draw_line(main, from_line, ofs, text_rect.size.x, base_color, outline_size, outline_color, font_shadow_color, use_outline, shadow_ofs); ofs.y += main->lines[from_line].text_buf->get_size().y; from_line++; } @@ -1423,7 +1479,7 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { return; } - if (b->get_button_index() == BUTTON_LEFT) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT) { if (b->is_pressed() && !b->is_doubleclick()) { scroll_updated = false; ItemFrame *c_frame = nullptr; @@ -1508,12 +1564,12 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { } } - if (b->get_button_index() == BUTTON_WHEEL_UP) { + if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { if (scroll_active) { vscroll->set_value(vscroll->get_value() - vscroll->get_page() * b->get_factor() * 0.5 / 8); } } - if (b->get_button_index() == BUTTON_WHEEL_DOWN) { + if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { if (scroll_active) { vscroll->set_value(vscroll->get_value() + vscroll->get_page() * b->get_factor() * 0.5 / 8); } @@ -1532,53 +1588,36 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { - if (k->is_pressed() && !k->get_alt() && !k->get_shift()) { + if (k->is_pressed()) { bool handled = false; - switch (k->get_keycode()) { - case KEY_PAGEUP: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() - vscroll->get_page()); - handled = true; - } - } break; - case KEY_PAGEDOWN: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() + vscroll->get_page()); - handled = true; - } - } break; - case KEY_UP: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); - handled = true; - } - } break; - case KEY_DOWN: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); - handled = true; - } - } break; - case KEY_HOME: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(0); - handled = true; - } - } break; - case KEY_END: { - if (vscroll->is_visible_in_tree()) { - vscroll->set_value(vscroll->get_max()); - handled = true; - } - } break; - case KEY_INSERT: - case KEY_C: { - if (k->get_command()) { - selection_copy(); - handled = true; - } - } break; + if (k->is_action("ui_page_up") && vscroll->is_visible_in_tree()) { + vscroll->set_value(vscroll->get_value() - vscroll->get_page()); + handled = true; + } + if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) { + vscroll->set_value(vscroll->get_value() + vscroll->get_page()); + handled = true; + } + if (k->is_action("ui_up") && vscroll->is_visible_in_tree()) { + vscroll->set_value(vscroll->get_value() - get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); + handled = true; + } + if (k->is_action("ui_down") && vscroll->is_visible_in_tree()) { + vscroll->set_value(vscroll->get_value() + get_theme_font("normal_font")->get_height(get_theme_font_size("normal_font_size"))); + handled = true; + } + if (k->is_action("ui_home") && vscroll->is_visible_in_tree()) { + vscroll->set_value(0); + handled = true; + } + if (k->is_action("ui_end") && vscroll->is_visible_in_tree()) { + vscroll->set_value(vscroll->get_max()); + handled = true; + } + if (k->is_action("ui_copy")) { + selection_copy(); + handled = true; } if (handled) { @@ -1712,7 +1751,7 @@ int RichTextLabel::_find_font_size(Item *p_item) { return -1; } -int RichTextLabel::_find_outline_size(Item *p_item) { +int RichTextLabel::_find_outline_size(Item *p_item, int p_default) { Item *sizeitem = p_item; while (sizeitem) { @@ -1724,7 +1763,7 @@ int RichTextLabel::_find_outline_size(Item *p_item) { sizeitem = sizeitem->parent; } - return 0; + return p_default; } Dictionary RichTextLabel::_find_font_features(Item *p_item) { @@ -1742,6 +1781,19 @@ Dictionary RichTextLabel::_find_font_features(Item *p_item) { return Dictionary(); } +RichTextLabel::ItemDropcap *RichTextLabel::_find_dc_item(Item *p_item) { + Item *item = p_item; + + while (item) { + if (item->type == ITEM_DROPCAP) { + return static_cast<ItemDropcap *>(item); + } + item = item->parent; + } + + return nullptr; +} + RichTextLabel::ItemList *RichTextLabel::_find_list_item(Item *p_item) { Item *item = p_item; @@ -1793,7 +1845,7 @@ int RichTextLabel::_find_list(Item *p_item, Vector<int> &r_index, Vector<ItemLis int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size) { Item *item = p_item; - float margin = 0; + float margin = 0.0; while (item) { if (item->type == ITEM_INDENT) { @@ -1805,7 +1857,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int if (font_size == -1) { font_size = p_base_font_size; } - margin += tab_size * font->get_char_size('m', 0, font_size).width; + margin += tab_size * font->get_char_size(' ', 0, font_size).width; } else if (item->type == ITEM_LIST) { Ref<Font> font = _find_font(item); @@ -1816,7 +1868,7 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font, int if (font_size == -1) { font_size = p_base_font_size; } - margin += tab_size * font->get_char_size('m', 0, font_size).width; + margin += tab_size * font->get_char_size(' ', 0, font_size).width; } item = item->parent; @@ -1960,46 +2012,6 @@ void RichTextLabel::_fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack } } -Color RichTextLabel::_get_color_from_string(const String &p_color_str, const Color &p_default_color) { - if (p_color_str.begins_with("#")) { - return Color::html(p_color_str); - } else if (p_color_str == "aqua") { - return Color(0, 1, 1); - } else if (p_color_str == "black") { - return Color(0, 0, 0); - } else if (p_color_str == "blue") { - return Color(0, 0, 1); - } else if (p_color_str == "fuchsia") { - return Color(1, 0, 1); - } else if (p_color_str == "gray" || p_color_str == "grey") { - return Color(0.5, 0.5, 0.5); - } else if (p_color_str == "green") { - return Color(0, 0.5, 0); - } else if (p_color_str == "lime") { - return Color(0, 1, 0); - } else if (p_color_str == "maroon") { - return Color(0.5, 0, 0); - } else if (p_color_str == "navy") { - return Color(0, 0, 0.5); - } else if (p_color_str == "olive") { - return Color(0.5, 0.5, 0); - } else if (p_color_str == "purple") { - return Color(0.5, 0, 0.5); - } else if (p_color_str == "red") { - return Color(1, 0, 0); - } else if (p_color_str == "silver") { - return Color(0.75, 0.75, 0.75); - } else if (p_color_str == "teal") { - return Color(0, 0.5, 0.5); - } else if (p_color_str == "white") { - return Color(1, 1, 1); - } else if (p_color_str == "yellow") { - return Color(1, 1, 0); - } else { - return p_default_color; - } -} - bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item) { Item *item = p_item; @@ -2238,6 +2250,8 @@ void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, } ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND(p_image->get_width() == 0); + ERR_FAIL_COND(p_image->get_height() == 0); ItemImage *item = memnew(ItemImage); item->image = p_image; @@ -2316,6 +2330,24 @@ bool RichTextLabel::remove_line(const int p_line) { return true; } +void RichTextLabel::push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins, const Color &p_color, int p_ol_size, const Color &p_ol_color) { + ERR_FAIL_COND(current->type == ITEM_TABLE); + ERR_FAIL_COND(p_string.is_empty()); + ERR_FAIL_COND(p_font.is_null()); + ERR_FAIL_COND(p_size <= 0); + + ItemDropcap *item = memnew(ItemDropcap); + + item->text = p_string; + item->font = p_font; + item->font_size = p_size; + item->color = p_color; + item->ol_size = p_ol_size; + item->ol_color = p_ol_color; + item->dropcap_margins = p_dropcap_margins; + _add_item(item, false); +} + void RichTextLabel::push_font(const Ref<Font> &p_font) { ERR_FAIL_COND(current->type == ITEM_TABLE); ERR_FAIL_COND(p_font.is_null()); @@ -2723,7 +2755,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { String bbcode_name; typedef Map<String, String> OptionMap; OptionMap bbcode_options; - if (!split_tag_block.empty()) { + if (!split_tag_block.is_empty()) { bbcode_name = split_tag_block[0]; for (int i = 1; i < split_tag_block.size(); i++) { const String &expr = split_tag_block[i]; @@ -2765,7 +2797,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { tag_stack.pop_front(); pos = brk_end + 1; - if (tag != "/img") { + if (tag != "/img" && tag != "/dropcap") { pop(); } @@ -2846,17 +2878,18 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { } } push_cell(); + const Color fallback_color = Color(0, 0, 0, 0); for (int i = 0; i < subtag.size(); i++) { Vector<String> subtag_a = subtag[i].split("="); if (subtag_a.size() == 2) { if (subtag_a[0] == "border") { - Color color = _get_color_from_string(subtag_a[1], Color(0, 0, 0, 0)); + Color color = Color::from_string(subtag_a[1], fallback_color); set_cell_border_color(color); } else if (subtag_a[0] == "bg") { Vector<String> subtag_b = subtag_a[1].split(","); if (subtag_b.size() == 2) { - Color color1 = _get_color_from_string(subtag_b[0], Color(0, 0, 0, 0)); - Color color2 = _get_color_from_string(subtag_b[1], Color(0, 0, 0, 0)); + Color color1 = Color::from_string(subtag_b[0], fallback_color); + Color color2 = Color::from_string(subtag_b[1], fallback_color); set_cell_row_background_color(color1, color2); } } @@ -3041,6 +3074,54 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { push_meta(url); pos = brk_end + 1; tag_stack.push_front("url"); + } else if (tag.begins_with("dropcap")) { + Vector<String> subtag = tag.substr(5, tag.length()).split(" "); + Ref<Font> f = get_theme_font("normal_font"); + int fs = get_theme_font_size("normal_font_size") * 3; + Color color = get_theme_color("default_color"); + Color outline_color = get_theme_color("outline_color"); + int outline_size = get_theme_constant("outline_size"); + Rect2 dropcap_margins = Rect2(); + + for (int i = 0; i < subtag.size(); i++) { + Vector<String> subtag_a = subtag[i].split("="); + if (subtag_a.size() == 2) { + if (subtag_a[0] == "font" || subtag_a[0] == "f") { + String fnt = subtag_a[1]; + Ref<Font> font = ResourceLoader::load(fnt, "Font"); + if (font.is_valid()) { + f = font; + } + } else if (subtag_a[0] == "font_size") { + fs = subtag_a[1].to_int(); + } else if (subtag_a[0] == "margins") { + Vector<String> subtag_b = subtag_a[1].split(","); + if (subtag_b.size() == 4) { + dropcap_margins.position.x = subtag_b[0].to_float(); + dropcap_margins.position.y = subtag_b[1].to_float(); + dropcap_margins.size.x = subtag_b[2].to_float(); + dropcap_margins.size.y = subtag_b[3].to_float(); + } + } else if (subtag_a[0] == "outline_size") { + outline_size = subtag_a[1].to_int(); + } else if (subtag_a[0] == "color") { + color = Color::from_string(subtag_a[1], color); + } else if (subtag_a[0] == "outline_color") { + outline_color = Color::from_string(subtag_a[1], outline_color); + } + } + } + int end = p_bbcode.find("[", brk_end); + if (end == -1) { + end = p_bbcode.length(); + } + + String txt = p_bbcode.substr(brk_end + 1, end - brk_end - 1); + + push_dropcap(txt, f, fs, dropcap_margins, color, outline_size, outline_color); + + pos = end; + tag_stack.push_front(bbcode_name); } else if (tag.begins_with("img")) { VAlign align = VALIGN_TOP; if (tag.begins_with("img=")) { @@ -3066,12 +3147,12 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { Color color = Color(1.0, 1.0, 1.0); OptionMap::Element *color_option = bbcode_options.find("color"); if (color_option) { - color = _get_color_from_string(color_option->value(), color); + color = Color::from_string(color_option->value(), color); } int width = 0; int height = 0; - if (!bbcode_value.empty()) { + if (!bbcode_value.is_empty()) { int sep = bbcode_value.find("x"); if (sep == -1) { width = bbcode_value.to_int(); @@ -3098,14 +3179,14 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { tag_stack.push_front(bbcode_name); } else if (tag.begins_with("color=")) { String color_str = tag.substr(6, tag.length()); - Color color = _get_color_from_string(color_str, base_color); + Color color = Color::from_string(color_str, base_color); push_color(color); pos = brk_end + 1; tag_stack.push_front("color"); } else if (tag.begins_with("outline_color=")) { String color_str = tag.substr(14, tag.length()); - Color color = _get_color_from_string(color_str, base_color); + Color color = Color::from_string(color_str, base_color); push_outline_color(color); pos = brk_end + 1; tag_stack.push_front("outline_color"); @@ -3299,14 +3380,46 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) { return OK; } +void RichTextLabel::scroll_to_paragraph(int p_paragraph) { + ERR_FAIL_INDEX(p_paragraph, main->lines.size()); + _validate_line_caches(main); + vscroll->set_value(main->lines[p_paragraph].offset.y); +} + +int RichTextLabel::get_paragraph_count() const { + return current_frame->lines.size(); +} + +int RichTextLabel::get_visible_paragraph_count() const { + if (!is_visible()) { + return 0; + } + return visible_paragraph_count; +} + void RichTextLabel::scroll_to_line(int p_line) { - ERR_FAIL_INDEX(p_line, main->lines.size()); _validate_line_caches(main); - vscroll->set_value(main->lines[p_line].offset.y); + + int line_count = 0; + for (int i = 0; i < main->lines.size(); i++) { + if ((line_count <= p_line) && (line_count + main->lines[i].text_buf->get_line_count() >= p_line)) { + float line_offset = 0.f; + for (int j = 0; j < p_line - line_count; j++) { + line_offset += main->lines[i].text_buf->get_line_size(j).y; + } + vscroll->set_value(main->lines[i].offset.y + line_offset); + return; + } + line_count += main->lines[i].text_buf->get_line_count(); + } } int RichTextLabel::get_line_count() const { - return current_frame->lines.size(); + int line_count = 0; + for (int i = 0; i < main->lines.size(); i++) { + line_count += main->lines[i].text_buf->get_line_count(); + } + return line_count; } int RichTextLabel::get_visible_line_count() const { @@ -3407,7 +3520,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p return false; } -String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) { +String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const { String text; ERR_FAIL_COND_V(p_frame == nullptr, text); ERR_FAIL_COND_V(p_line < 0 || p_line >= p_frame->lines.size(), text); @@ -3474,7 +3587,7 @@ String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p return text; } -String RichTextLabel::get_selected_text() { +String RichTextLabel::get_selected_text() const { if (!selection.active || !selection.enabled) { return ""; } @@ -3498,6 +3611,22 @@ bool RichTextLabel::is_selection_enabled() const { return selection.enabled; } +int RichTextLabel::get_selection_from() const { + if (!selection.active || !selection.enabled) { + return -1; + } + + return selection.from_frame->lines[selection.from_line].char_offset + selection.from_char; +} + +int RichTextLabel::get_selection_to() const { + if (!selection.active || !selection.enabled) { + return -1; + } + + return selection.to_frame->lines[selection.to_line].char_offset + selection.to_char - 1; +} + void RichTextLabel::set_bbcode(const String &p_bbcode) { bbcode = p_bbcode; if (is_inside_tree() && use_bbcode) { @@ -3518,6 +3647,7 @@ void RichTextLabel::set_use_bbcode(bool p_enable) { } use_bbcode = p_enable; set_bbcode(bbcode); + notify_property_list_changed(); } bool RichTextLabel::is_using_bbcode() const { @@ -3533,6 +3663,8 @@ String RichTextLabel::get_text() { text += t->text; } else if (it->type == ITEM_NEWLINE) { text += "\n"; + } else if (it->type == ITEM_IMAGE) { + text += " "; } else if (it->type == ITEM_INDENT || it->type == ITEM_LIST) { text += "\t"; } @@ -3624,7 +3756,9 @@ void RichTextLabel::set_effects(const Vector<Variant> &effects) { custom_effects.push_back(effect); } - parse_bbcode(bbcode); + if ((bbcode != "") && use_bbcode) { + parse_bbcode(bbcode); + } } Vector<Variant> RichTextLabel::get_effects() { @@ -3641,7 +3775,9 @@ void RichTextLabel::install_effect(const Variant effect) { if (rteffect.is_valid()) { custom_effects.push_back(effect); - parse_bbcode(bbcode); + if ((bbcode != "") && use_bbcode) { + parse_bbcode(bbcode); + } } } @@ -3653,6 +3789,12 @@ int RichTextLabel::get_content_height() const { return total_height; } +void RichTextLabel::_validate_property(PropertyInfo &property) const { + if (!use_bbcode && property.name == "bbcode_text") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("_gui_input"), &RichTextLabel::_gui_input); ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text); @@ -3679,6 +3821,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline); ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough); ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP)); + ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0))); ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand); ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color); ClassDB::bind_method(D_METHOD("set_cell_border_color", "color"), &RichTextLabel::set_cell_border_color); @@ -3713,6 +3856,7 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_v_scroll"), &RichTextLabel::get_v_scroll); ClassDB::bind_method(D_METHOD("scroll_to_line", "line"), &RichTextLabel::scroll_to_line); + ClassDB::bind_method(D_METHOD("scroll_to_paragraph", "paragraph"), &RichTextLabel::scroll_to_paragraph); ClassDB::bind_method(D_METHOD("set_tab_size", "spaces"), &RichTextLabel::set_tab_size); ClassDB::bind_method(D_METHOD("get_tab_size"), &RichTextLabel::get_tab_size); @@ -3723,6 +3867,11 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("set_selection_enabled", "enabled"), &RichTextLabel::set_selection_enabled); ClassDB::bind_method(D_METHOD("is_selection_enabled"), &RichTextLabel::is_selection_enabled); + ClassDB::bind_method(D_METHOD("get_selection_from"), &RichTextLabel::get_selection_from); + ClassDB::bind_method(D_METHOD("get_selection_to"), &RichTextLabel::get_selection_to); + + ClassDB::bind_method(D_METHOD("get_selected_text"), &RichTextLabel::get_selected_text); + ClassDB::bind_method(D_METHOD("parse_bbcode", "bbcode"), &RichTextLabel::parse_bbcode); ClassDB::bind_method(D_METHOD("append_bbcode", "bbcode"), &RichTextLabel::append_bbcode); @@ -3743,6 +3892,9 @@ void RichTextLabel::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_count"), &RichTextLabel::get_line_count); ClassDB::bind_method(D_METHOD("get_visible_line_count"), &RichTextLabel::get_visible_line_count); + ClassDB::bind_method(D_METHOD("get_paragraph_count"), &RichTextLabel::get_paragraph_count); + ClassDB::bind_method(D_METHOD("get_visible_paragraph_count"), &RichTextLabel::get_visible_paragraph_count); + ClassDB::bind_method(D_METHOD("get_content_height"), &RichTextLabel::get_content_height); ClassDB::bind_method(D_METHOD("parse_expressions_for_values", "expressions"), &RichTextLabel::parse_expressions_for_values); @@ -3814,12 +3966,21 @@ void RichTextLabel::_bind_methods() { BIND_ENUM_CONSTANT(ITEM_WAVE); BIND_ENUM_CONSTANT(ITEM_TORNADO); BIND_ENUM_CONSTANT(ITEM_RAINBOW); - BIND_ENUM_CONSTANT(ITEM_CUSTOMFX); BIND_ENUM_CONSTANT(ITEM_META); + BIND_ENUM_CONSTANT(ITEM_DROPCAP); + BIND_ENUM_CONSTANT(ITEM_CUSTOMFX); } void RichTextLabel::set_visible_characters(int p_visible) { visible_characters = p_visible; + if (p_visible == -1) { + percent_visible = 1; + } else { + int total_char_count = get_total_character_count(); + if (total_char_count > 0) { + percent_visible = (float)p_visible / (float)total_char_count; + } + } update(); } @@ -3842,14 +4003,16 @@ void RichTextLabel::set_fixed_size_to_width(int p_width) { } Size2 RichTextLabel::get_minimum_size() const { - Size2 size(0, 0); + Ref<StyleBox> style = get_theme_stylebox("normal"); + Size2 size = style->get_minimum_size(); + if (fixed_width != -1) { - size.x = fixed_width; + size.x += fixed_width; } if (fixed_width != -1 || fit_content_height) { const_cast<RichTextLabel *>(this)->_validate_line_caches(main); - size.y = get_content_height(); + size.y += get_content_height(); } return size; @@ -3937,43 +4100,17 @@ RichTextLabel::RichTextLabel() { main->first_invalid_line = 0; main->first_resized_line = 0; current_frame = main; - tab_size = 4; - default_align = ALIGN_LEFT; - underline_meta = true; - meta_hovering = nullptr; - override_selected_font_color = false; - - scroll_visible = false; - scroll_follow = false; - scroll_following = false; - updating_scroll = false; - scroll_active = true; - scroll_w = 0; - scroll_updated = false; vscroll = memnew(VScrollBar); add_child(vscroll); vscroll->set_drag_node(String("..")); vscroll->set_step(1); - vscroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); - vscroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); - vscroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); + vscroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); + vscroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); + vscroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); vscroll->connect("value_changed", callable_mp(this, &RichTextLabel::_scroll_changed)); vscroll->set_step(1); vscroll->hide(); - use_bbcode = false; - - selection.click_frame = nullptr; - selection.click_item = nullptr; - selection.active = false; - selection.enabled = false; - - visible_characters = -1; - percent_visible = 1; - visible_line_count = 0; - - fixed_width = -1; - fit_content_height = false; set_clip_contents(true); } diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index f1dac69dce..e3e457d1f2 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -76,11 +76,14 @@ public: ITEM_TORNADO, ITEM_RAINBOW, ITEM_META, + ITEM_DROPCAP, ITEM_CUSTOMFX }; protected: + void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; private: struct Item; @@ -89,6 +92,9 @@ private: Item *from = nullptr; Ref<TextParagraph> text_buf; + Color dc_color; + int dc_ol_size = 0; + Color dc_ol_color; Vector2 offset; int char_offset = 0; @@ -140,6 +146,17 @@ private: ItemText() { type = ITEM_TEXT; } }; + struct ItemDropcap : public Item { + String text; + Ref<Font> font; + int font_size = 0; + Color color; + int ol_size = 0; + Color ol_color; + Rect2 dropcap_margins; + ItemDropcap() { type = ITEM_DROPCAP; } + }; + struct ItemImage : public Item { Ref<Texture2D> image; VAlign inline_align = VALIGN_TOP; @@ -217,11 +234,11 @@ private: struct ItemTable : public Item { struct Column { - bool expand; - int expand_ratio; - int min_width; - int max_width; - int width; + bool expand = false; + int expand_ratio = 0; + int min_width = 0; + int max_width = 0; + int width = 0; }; Vector<Column> columns; @@ -307,30 +324,31 @@ private: } }; - ItemFrame *main; - Item *current; - ItemFrame *current_frame; + ItemFrame *main = nullptr; + Item *current = nullptr; + ItemFrame *current_frame = nullptr; - VScrollBar *vscroll; + VScrollBar *vscroll = nullptr; - bool scroll_visible; - bool scroll_follow; - bool scroll_following; - bool scroll_active; - int scroll_w; - bool scroll_updated; - bool updating_scroll; + bool scroll_visible = false; + bool scroll_follow = false; + bool scroll_following = false; + bool scroll_active = true; + int scroll_w = 0; + bool scroll_updated = false; + bool updating_scroll = false; int current_idx = 1; int current_char_ofs = 0; - int visible_line_count; + int visible_paragraph_count = 0; + int visible_line_count = 0; - int tab_size; - bool underline_meta; - bool override_selected_font_color; + int tab_size = 4; + bool underline_meta = true; + bool override_selected_font_color = false; - Align default_align; + Align default_align = ALIGN_LEFT; - ItemMeta *meta_hovering; + ItemMeta *meta_hovering = nullptr; Variant current_meta; Vector<Ref<RichTextEffect>> custom_effects; @@ -347,38 +365,38 @@ private: Array st_args; struct Selection { - ItemFrame *click_frame; - int click_line; - Item *click_item; - int click_char; - - ItemFrame *from_frame; - int from_line; - Item *from_item; - int from_char; - - ItemFrame *to_frame; - int to_line; - Item *to_item; - int to_char; - - bool active; // anything selected? i.e. from, to, etc. valid? - bool enabled; // allow selections? + ItemFrame *click_frame = nullptr; + int click_line = 0; + Item *click_item = nullptr; + int click_char = 0; + + ItemFrame *from_frame = nullptr; + int from_line = 0; + Item *from_item = nullptr; + int from_char = 0; + + ItemFrame *to_frame = nullptr; + int to_line = 0; + Item *to_item = nullptr; + int to_char = 0; + + bool active = false; // anything selected? i.e. from, to, etc. valid? + bool enabled = false; // allow selections? }; Selection selection; - int visible_characters; - float percent_visible; + int visible_characters = -1; + float percent_visible = 1.0; void _find_click(ItemFrame *p_frame, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr, bool *r_outside = nullptr); - String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel); + String _get_line_text(ItemFrame *p_frame, int p_line, Selection p_sel) const; bool _search_line(ItemFrame *p_frame, int p_line, const String &p_string, Item *p_from, Item *p_to); void _shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, int *r_char_offset); void _resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width); - void _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs); + int _draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, bool p_shadow_as_outline, const Point2 &shadow_ofs); float _find_click_in_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Point2i &p_click, ItemFrame **r_click_frame = nullptr, int *r_click_line = nullptr, Item **r_click_item = nullptr, int *r_click_char = nullptr); String _roman(int p_num, bool p_capitalize) const; @@ -389,8 +407,9 @@ private: Ref<Font> _find_font(Item *p_item); int _find_font_size(Item *p_item); Dictionary _find_font_features(Item *p_item); - int _find_outline_size(Item *p_item); + int _find_outline_size(Item *p_item, int p_default); ItemList *_find_list_item(Item *p_item); + ItemDropcap *_find_dc_item(Item *p_item); int _find_list(Item *p_item, Vector<int> &r_index, Vector<ItemList *> &r_list); int _find_margin(Item *p_item, const Ref<Font> &p_base_font, int p_base_font_size); Align _find_align(Item *p_item); @@ -405,29 +424,24 @@ private: bool _find_layout_subitem(Item *from, Item *to); void _fetch_item_fx_stack(Item *p_item, Vector<ItemFX *> &r_stack); - static Color _get_color_from_string(const String &p_color_str, const Color &p_default_color); - void _update_scroll(); void _update_fx(ItemFrame *p_frame, float p_delta_time); void _scroll_changed(double); void _gui_input(Ref<InputEvent> p_event); - Item *_get_next_item(Item *p_item, bool p_free = false); - Item *_get_prev_item(Item *p_item, bool p_free = false); + Item *_get_next_item(Item *p_item, bool p_free = false) const; + Item *_get_prev_item(Item *p_item, bool p_free = false) const; Rect2 _get_text_rect(); Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier); virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions); - bool use_bbcode; + bool use_bbcode = false; String bbcode; - int fixed_width; + int fixed_width = -1; - bool fit_content_height; - -protected: - void _notification(int p_what); + bool fit_content_height = false; public: String get_text(); @@ -435,6 +449,7 @@ public: void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP); void add_newline(); bool remove_line(const int p_line); + void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0)); void push_font(const Ref<Font> &p_font); void push_font_size(int p_font_size); void push_font_features(const Dictionary &p_features); @@ -492,6 +507,10 @@ public: bool search(const String &p_string, bool p_from_selection = false, bool p_search_previous = false); + void scroll_to_paragraph(int p_paragraph); + int get_paragraph_count() const; + int get_visible_paragraph_count() const; + void scroll_to_line(int p_line); int get_line_count() const; int get_visible_line_count() const; @@ -504,7 +523,9 @@ public: void set_selection_enabled(bool p_enabled); bool is_selection_enabled() const; - String get_selected_text(); + int get_selection_from() const; + int get_selection_to() const; + String get_selected_text() const; 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 70de63fd40..a56bf15507 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -52,17 +52,17 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) { if (b.is_valid()) { accept_event(); - if (b->get_button_index() == BUTTON_WHEEL_DOWN && b->is_pressed()) { + if (b->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && b->is_pressed()) { set_value(get_value() + get_page() / 4.0); accept_event(); } - if (b->get_button_index() == BUTTON_WHEEL_UP && b->is_pressed()) { + if (b->get_button_index() == MOUSE_BUTTON_WHEEL_UP && b->is_pressed()) { set_value(get_value() - get_page() / 4.0); accept_event(); } - if (b->get_button_index() != BUTTON_LEFT) { + if (b->get_button_index() != MOUSE_BUTTON_LEFT) { return; } @@ -259,11 +259,11 @@ void ScrollBar::_notification(int p_what) { grabber_rect.size.width = get_grabber_size(); grabber_rect.size.height = get_size().height; grabber_rect.position.y = 0; - grabber_rect.position.x = get_grabber_offset() + decr->get_width() + bg->get_margin(MARGIN_LEFT); + grabber_rect.position.x = get_grabber_offset() + decr->get_width() + bg->get_margin(SIDE_LEFT); } else { grabber_rect.size.width = get_size().width; grabber_rect.size.height = get_grabber_size(); - grabber_rect.position.y = get_grabber_offset() + decr->get_height() + bg->get_margin(MARGIN_TOP); + grabber_rect.position.y = get_grabber_offset() + decr->get_height() + bg->get_margin(SIDE_TOP); grabber_rect.position.x = 0; } @@ -434,15 +434,15 @@ double ScrollBar::get_area_size() const { } double ScrollBar::get_area_offset() const { - double ofs = 0; + double ofs = 0.0; if (orientation == VERTICAL) { - ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_TOP); + ofs += get_theme_stylebox("hscroll")->get_margin(SIDE_TOP); ofs += get_theme_icon("decrement")->get_height(); } if (orientation == HORIZONTAL) { - ofs += get_theme_stylebox("hscroll")->get_margin(MARGIN_LEFT); + ofs += get_theme_stylebox("hscroll")->get_margin(SIDE_LEFT); ofs += get_theme_icon("decrement")->get_width(); } diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 358ed74965..24b3b33e82 100644 --- a/scene/gui/scroll_bar.h +++ b/scene/gui/scroll_bar.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,14 +47,14 @@ class ScrollBar : public Range { Orientation orientation; Size2 size; - float custom_step = -1; + float custom_step = -1.0; HighlightStatus highlight = HIGHLIGHT_NONE; struct Drag { bool active = false; - float pos_at_click = 0; - float value_at_click = 0; + float pos_at_click = 0.0; + float value_at_click = 0.0; } drag; double get_grabber_size() const; @@ -73,14 +73,14 @@ class ScrollBar : public Range { Vector2 drag_node_accum; Vector2 drag_node_from; Vector2 last_drag_node_accum; - float last_drag_node_time; - float time_since_motion; + float last_drag_node_time = 0.0; + float time_since_motion = 0.0; bool drag_node_touching = false; bool drag_node_touching_deaccel = false; - bool click_handled; + bool click_handled = false; bool scrolling = false; - double target_scroll = 0; + double target_scroll = 0.0; bool smooth_scroll_enabled = false; void _drag_node_exit(); diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 4110a971c8..90a528482f 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -94,7 +94,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { Ref<InputEventMouseButton> mb = p_gui_input; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() / 8 * mb->get_factor()); @@ -103,7 +103,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - if (mb->get_button_index() == BUTTON_WHEEL_DOWN && mb->is_pressed()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && mb->is_pressed()) { // only horizontal is enabled, scroll horizontally if (h_scroll->is_visible() && (!v_scroll->is_visible() || mb->get_shift())) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() / 8 * mb->get_factor()); @@ -112,13 +112,13 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - if (mb->get_button_index() == BUTTON_WHEEL_LEFT && mb->is_pressed()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT && mb->is_pressed()) { if (h_scroll->is_visible_in_tree()) { h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb->get_factor() / 8); } } - if (mb->get_button_index() == BUTTON_WHEEL_RIGHT && mb->is_pressed()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT && mb->is_pressed()) { if (h_scroll->is_visible_in_tree()) { h_scroll->set_value(h_scroll->get_value() + h_scroll->get_page() * mb->get_factor() / 8); } @@ -132,7 +132,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - if (mb->get_button_index() != BUTTON_LEFT) { + if (mb->get_button_index() != MOUSE_BUTTON_LEFT) { return; } @@ -220,15 +220,15 @@ void ScrollContainer::_update_scrollbar_position() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - h_scroll->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_BEGIN, 0); - h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - h_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_END, -hmin.height); - h_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + h_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -hmin.height); + h_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); - v_scroll->set_anchor_and_margin(MARGIN_LEFT, ANCHOR_END, -vmin.width); - v_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, 0); - v_scroll->set_anchor_and_margin(MARGIN_TOP, ANCHOR_BEGIN, 0); - v_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -vmin.width); + v_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0); + v_scroll->set_anchor_and_offset(SIDE_TOP, ANCHOR_BEGIN, 0); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0); h_scroll->raise(); v_scroll->raise(); @@ -244,11 +244,11 @@ void ScrollContainer::_ensure_focused_visible(Control *p_control) { if (is_a_parent_of(p_control)) { Rect2 global_rect = get_global_rect(); Rect2 other_rect = p_control->get_global_rect(); - float right_margin = 0; + float right_margin = 0.0; if (v_scroll->is_visible()) { right_margin += v_scroll->get_size().x; } - float bottom_margin = 0; + float bottom_margin = 0.0; if (h_scroll->is_visible()) { bottom_margin += h_scroll->get_size().y; } @@ -264,6 +264,67 @@ void ScrollContainer::_ensure_focused_visible(Control *p_control) { } } +void ScrollContainer::_update_dimensions() { + child_max_size = Size2(0, 0); + Size2 size = get_size(); + Point2 ofs; + + Ref<StyleBox> sb = get_theme_stylebox("bg"); + size -= sb->get_minimum_size(); + ofs += sb->get_offset(); + bool rtl = is_layout_rtl(); + + if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + size.y -= h_scroll->get_minimum_size().y; + } + + if (v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { //scrolls may have been moved out for reasons + size.x -= v_scroll->get_minimum_size().x; + } + + for (int i = 0; i < get_child_count(); i++) { + Control *c = Object::cast_to<Control>(get_child(i)); + if (!c) { + continue; + } + if (c->is_set_as_top_level()) { + continue; + } + if (c == h_scroll || c == v_scroll) { + continue; + } + Size2 minsize = c->get_combined_minimum_size(); + child_max_size.x = MAX(child_max_size.x, minsize.x); + child_max_size.y = MAX(child_max_size.y, minsize.y); + + Rect2 r = Rect2(-scroll, minsize); + if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) { + r.position.x = 0; + if (c->get_h_size_flags() & SIZE_EXPAND) { + r.size.width = MAX(size.width, minsize.width); + } else { + r.size.width = minsize.width; + } + } + if (!scroll_v || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) { + r.position.y = 0; + if (c->get_v_size_flags() & SIZE_EXPAND) { + r.size.height = MAX(size.height, minsize.height); + } else { + r.size.height = minsize.height; + } + } + r.position += ofs; + if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { + r.position.x += v_scroll->get_minimum_size().x; + } + r.position = r.position.floor(); + fit_child_in_rect(c, r); + } + + update(); +} + void ScrollContainer::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_LAYOUT_DIRECTION_CHANGED || p_what == NOTIFICATION_TRANSLATION_CHANGED) { _updating_scrollbars = true; @@ -272,67 +333,11 @@ void ScrollContainer::_notification(int p_what) { if (p_what == NOTIFICATION_READY) { get_viewport()->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_ensure_focused_visible)); + _update_dimensions(); } if (p_what == NOTIFICATION_SORT_CHILDREN) { - child_max_size = Size2(0, 0); - Size2 size = get_size(); - Point2 ofs; - - Ref<StyleBox> sb = get_theme_stylebox("bg"); - size -= sb->get_minimum_size(); - ofs += sb->get_offset(); - bool rtl = is_layout_rtl(); - - if (h_scroll->is_visible_in_tree() && h_scroll->get_parent() == this) { //scrolls may have been moved out for reasons - size.y -= h_scroll->get_minimum_size().y; - } - - if (v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { //scrolls may have been moved out for reasons - size.x -= v_scroll->get_minimum_size().x; - } - - for (int i = 0; i < get_child_count(); i++) { - Control *c = Object::cast_to<Control>(get_child(i)); - if (!c) { - continue; - } - if (c->is_set_as_top_level()) { - continue; - } - if (c == h_scroll || c == v_scroll) { - continue; - } - Size2 minsize = c->get_combined_minimum_size(); - child_max_size.x = MAX(child_max_size.x, minsize.x); - child_max_size.y = MAX(child_max_size.y, minsize.y); - - Rect2 r = Rect2(-scroll, minsize); - if (!scroll_h || (!h_scroll->is_visible_in_tree() && c->get_h_size_flags() & SIZE_EXPAND)) { - r.position.x = 0; - if (c->get_h_size_flags() & SIZE_EXPAND) { - r.size.width = MAX(size.width, minsize.width); - } else { - r.size.width = minsize.width; - } - } - if (!scroll_v || (!v_scroll->is_visible_in_tree() && c->get_v_size_flags() & SIZE_EXPAND)) { - r.position.y = 0; - if (c->get_v_size_flags() & SIZE_EXPAND) { - r.size.height = MAX(size.height, minsize.height); - } else { - r.size.height = minsize.height; - } - } - r.position += ofs; - if (rtl && v_scroll->is_visible_in_tree() && v_scroll->get_parent() == this) { - r.position.x += v_scroll->get_minimum_size().x; - } - r.position = r.position.floor(); - fit_child_in_rect(c, r); - } - - update(); + _update_dimensions(); }; if (p_what == NOTIFICATION_DRAW) { @@ -463,8 +468,8 @@ void ScrollContainer::update_scrollbars() { } // Avoid scrollbar overlapping. - h_scroll->set_anchor_and_margin(MARGIN_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width); - v_scroll->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_END, hide_scroll_h ? 0 : -hmin.height); + h_scroll->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, hide_scroll_v ? 0 : -vmin.width); + v_scroll->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, hide_scroll_h ? 0 : -hmin.height); } void ScrollContainer::_scroll_moved(float) { @@ -558,7 +563,7 @@ String ScrollContainer::get_configuration_warning() const { } if (found != 1) { - if (!warning.empty()) { + if (!warning.is_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."); @@ -619,15 +624,7 @@ ScrollContainer::ScrollContainer() { add_child(v_scroll); v_scroll->connect("value_changed", callable_mp(this, &ScrollContainer::_scroll_moved)); - drag_speed = Vector2(); - drag_touching = false; - drag_touching_deaccel = false; - beyond_deadzone = false; - scroll_h = true; - scroll_v = true; - deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone"); - follow_focus = false; set_clip_contents(true); }; diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h index 4bf200009e..9d3ce39345 100644 --- a/scene/gui/scroll_container.h +++ b/scene/gui/scroll_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,18 +50,18 @@ class ScrollContainer : public Container { Vector2 drag_accum; Vector2 drag_from; Vector2 last_drag_accum; - float last_drag_time; - float time_since_motion; - bool drag_touching; - bool drag_touching_deaccel; - bool click_handled; - bool beyond_deadzone; + float last_drag_time = 0.0; + float time_since_motion = 0.0; + bool drag_touching = false; + bool drag_touching_deaccel = false; + bool click_handled = false; + bool beyond_deadzone = false; - bool scroll_h; - bool scroll_v; + bool scroll_h = true; + bool scroll_v = true; - int deadzone; - bool follow_focus; + int deadzone = 0; + bool follow_focus = false; void _cancel_drag(); @@ -69,6 +69,7 @@ protected: Size2 get_minimum_size() const override; void _gui_input(const Ref<InputEvent> &p_gui_input); + void _update_dimensions(); void _notification(int p_what); void _scroll_moved(float); diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp index 4f7e5720b8..3cb8ccf135 100644 --- a/scene/gui/separator.cpp +++ b/scene/gui/separator.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/separator.h b/scene/gui/separator.h index eec989cfea..77162c68fa 100644 --- a/scene/gui/separator.h +++ b/scene/gui/separator.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class Separator : public Control { GDCLASS(Separator, Control); protected: - Orientation orientation; + Orientation orientation = Orientation::HORIZONTAL; void _notification(int p_what); public: diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp index f8c7bc44a7..cbbcf9e069 100644 --- a/scene/gui/shortcut.cpp +++ b/scene/gui/shortcut.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h index 176958b397..ea91f29b5d 100644 --- a/scene/gui/shortcut.h +++ b/scene/gui/shortcut.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 3dd5e022f0..7f1d19a87a 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -53,7 +53,7 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { Ref<Texture2D> grabber = get_theme_icon(mouse_inside || has_focus() ? "grabber_highlight" : "grabber"); grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x; @@ -72,9 +72,11 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { grab.active = false; } } else if (scrollable) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) { + if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { + grab_focus(); set_value(get_value() + get_step()); - } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) { + } else if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { + grab_focus(); set_value(get_value() - get_step()); } } @@ -269,12 +271,5 @@ void Slider::_bind_methods() { Slider::Slider(Orientation p_orientation) { orientation = p_orientation; - mouse_inside = false; - grab.active = false; - ticks = 0; - ticks_on_borders = false; - custom_step = -1; - editable = true; - scrollable = true; set_focus_mode(FOCUS_ALL); } diff --git a/scene/gui/slider.h b/scene/gui/slider.h index b4b56f2856..65a4036cd1 100644 --- a/scene/gui/slider.h +++ b/scene/gui/slider.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,23 +37,23 @@ class Slider : public Range { GDCLASS(Slider, Range); struct Grab { - int pos; - float uvalue; - bool active; + int pos = 0; + float uvalue = 0.0; + bool active = false; } grab; - int ticks; - bool mouse_inside; + int ticks = 0; + bool mouse_inside = false; Orientation orientation; - float custom_step; - bool editable; - bool scrollable; + float custom_step = -1.0; + bool editable = true; + bool scrollable = true; protected: void _gui_input(Ref<InputEvent> p_event); void _notification(int p_what); static void _bind_methods(); - bool ticks_on_borders; + bool ticks_on_borders = false; public: virtual Size2 get_minimum_size() const override; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 46b24efed5..50b25fa7b4 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -76,7 +76,7 @@ void SpinBox::_line_edit_input(const Ref<InputEvent> &p_event) { } void SpinBox::_range_click_timeout() { - if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) { bool up = get_local_mouse_position().y < (get_size().height / 2); set_value(get_value() + (up ? get_step() : -get_step())); @@ -91,6 +91,14 @@ void SpinBox::_range_click_timeout() { } } +void SpinBox::_release_mouse() { + if (drag.enabled) { + drag.enabled = false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(drag.capture_pos); + } +} + void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { if (!is_editable()) { return; @@ -102,7 +110,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { bool up = mb->get_position().y < (get_size().height / 2); switch (mb->get_button_index()) { - case BUTTON_LEFT: { + case MOUSE_BUTTON_LEFT: { line_edit->grab_focus(); set_value(get_value() + (up ? get_step() : -get_step())); @@ -114,17 +122,17 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { drag.allowed = true; drag.capture_pos = mb->get_position(); } break; - case BUTTON_RIGHT: { + case MOUSE_BUTTON_RIGHT: { line_edit->grab_focus(); set_value((up ? get_max() : get_min())); } break; - case BUTTON_WHEEL_UP: { + case MOUSE_BUTTON_WHEEL_UP: { if (line_edit->has_focus()) { set_value(get_value() + get_step() * mb->get_factor()); accept_event(); } } break; - case BUTTON_WHEEL_DOWN: { + case MOUSE_BUTTON_WHEEL_DOWN: { if (line_edit->has_focus()) { set_value(get_value() - get_step() * mb->get_factor()); accept_event(); @@ -133,21 +141,16 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { } } - if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { //set_default_cursor_shape(CURSOR_ARROW); range_click_timer->stop(); - - if (drag.enabled) { - drag.enabled = false; - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - warp_mouse(drag.capture_pos); - } + _release_mouse(); drag.allowed = false; } Ref<InputEventMouseMotion> mm = p_event; - if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { + if (mm.is_valid() && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { if (drag.enabled) { drag.diff_y += mm->get_relative().y; float diff_y = -0.01 * Math::pow(ABS(drag.diff_y), 1.8f) * SGN(drag.diff_y); @@ -173,8 +176,8 @@ void SpinBox::_line_edit_focus_exit() { inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) { int w = icon->get_width(); if ((w != last_w)) { - line_edit->set_margin(MARGIN_LEFT, 0); - line_edit->set_margin(MARGIN_RIGHT, -w); + line_edit->set_offset(SIDE_LEFT, 0); + line_edit->set_offset(SIDE_RIGHT, -w); last_w = w; } } @@ -199,6 +202,8 @@ void SpinBox::_notification(int p_what) { } else if (p_what == NOTIFICATION_ENTER_TREE) { _adjust_width_for_icon(get_theme_icon("updown")); _value_changed(0); + } else if (p_what == NOTIFICATION_EXIT_TREE) { + _release_mouse(); } else if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { _value_changed(0); } else if (p_what == NOTIFICATION_THEME_CHANGED) { @@ -268,11 +273,10 @@ void SpinBox::_bind_methods() { } SpinBox::SpinBox() { - last_w = 0; line_edit = memnew(LineEdit); add_child(line_edit); - line_edit->set_anchors_and_margins_preset(Control::PRESET_WIDE); + line_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE); line_edit->set_mouse_filter(MOUSE_FILTER_PASS); line_edit->set_align(LineEdit::ALIGN_LEFT); @@ -280,7 +284,6 @@ SpinBox::SpinBox() { line_edit->connect("text_entered", callable_mp(this, &SpinBox::_text_entered), Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("focus_exited", callable_mp(this, &SpinBox::_line_edit_focus_exit), Vector<Variant>(), CONNECT_DEFERRED); line_edit->connect("gui_input", callable_mp(this, &SpinBox::_line_edit_input)); - drag.enabled = false; range_click_timer = memnew(Timer); range_click_timer->connect("timeout", callable_mp(this, &SpinBox::_range_click_timeout)); diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 1b3dc9d79e..e116adb64c 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,10 +39,11 @@ class SpinBox : public Range { GDCLASS(SpinBox, Range); LineEdit *line_edit; - int last_w; + int last_w = 0; Timer *range_click_timer; void _range_click_timeout(); + void _release_mouse(); void _text_entered(const String &p_string); virtual void _value_changed(double) override; @@ -52,11 +53,11 @@ class SpinBox : public Range { void _line_edit_input(const Ref<InputEvent> &p_event); struct Drag { - float base_val; - bool allowed; - bool enabled; + float base_val = 0.0; + bool allowed = false; + bool enabled = false; Vector2 capture_pos; - float diff_y; + float diff_y = 0.0; } drag; void _line_edit_focus_exit(); diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index 1e85bba0e3..c80120f87d 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -102,7 +102,7 @@ void SplitContainer::_resort() { middle_sep += clamped_split_offset; if (should_clamp_split_offset) { split_offset = clamped_split_offset; - _change_notify("split_offset"); + should_clamp_split_offset = false; } } @@ -214,7 +214,7 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->is_pressed()) { int sep = get_theme_constant("separation"); @@ -359,12 +359,5 @@ void SplitContainer::_bind_methods() { } SplitContainer::SplitContainer(bool p_vertical) { - mouse_inside = false; - split_offset = 0; - should_clamp_split_offset = false; - middle_sep = 0; vertical = p_vertical; - dragging = false; - collapsed = false; - dragger_visibility = DRAGGER_VISIBLE; } diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h index e345016f3d..6cb94d6ecf 100644 --- a/scene/gui/split_container.h +++ b/scene/gui/split_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,16 +44,16 @@ public: }; private: - bool should_clamp_split_offset; - int split_offset; - int middle_sep; - bool vertical; - bool dragging; - int drag_from; - int drag_ofs; - bool collapsed; - DraggerVisibility dragger_visibility; - bool mouse_inside; + bool should_clamp_split_offset = false; + int split_offset = 0; + int middle_sep = 0; + bool vertical = false; + bool dragging = false; + int drag_from = 0; + int drag_ofs = 0; + bool collapsed = false; + DraggerVisibility dragger_visibility = DRAGGER_VISIBLE; + bool mouse_inside = false; Control *_getch(int p_idx) const; diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index c5f56fe8e2..8ffdd269a4 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -203,8 +203,6 @@ void SubViewportContainer::_bind_methods() { } SubViewportContainer::SubViewportContainer() { - stretch = false; - shrink = 1; set_process_input(true); set_process_unhandled_input(true); } diff --git a/scene/gui/subviewport_container.h b/scene/gui/subviewport_container.h index e82ad772ce..77cf4c16b3 100644 --- a/scene/gui/subviewport_container.h +++ b/scene/gui/subviewport_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,8 +36,8 @@ class SubViewportContainer : public Container { GDCLASS(SubViewportContainer, Container); - bool stretch; - int shrink; + bool stretch = false; + int shrink = 1; protected: void _notification(int p_what); diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 809b4ffd64..1e31f9e206 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,11 +43,11 @@ int TabContainer::_get_top_margin() const { } // Respect the minimum tab height. - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); - int tab_height = MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height); + int tab_height = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height); // Font height or higher icon wins. int content_height = 0; @@ -76,7 +76,7 @@ void TabContainer::_gui_input(const Ref<InputEvent> &p_event) { Popup *popup = get_popup(); - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { Point2 pos(mb->get_position().x, mb->get_position().y); Size2 size = get_size(); @@ -337,8 +337,8 @@ void TabContainer::_notification(int p_what) { } Vector<Control *> tabs = _get_tabs(); - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); Ref<Texture2D> increment = get_theme_icon("increment"); Ref<Texture2D> increment_hl = get_theme_icon("increment_highlight"); @@ -346,9 +346,9 @@ void TabContainer::_notification(int p_what) { Ref<Texture2D> decrement_hl = get_theme_icon("decrement_highlight"); Ref<Texture2D> menu = get_theme_icon("menu"); Ref<Texture2D> menu_hl = get_theme_icon("menu_highlight"); - Color font_color_fg = get_theme_color("font_color_fg"); - Color font_color_bg = get_theme_color("font_color_bg"); - Color font_color_disabled = get_theme_color("font_color_disabled"); + Color font_selected_color = get_theme_color("font_selected_color"); + Color font_unselected_color = get_theme_color("font_unselected_color"); + Color font_disabled_color = get_theme_color("font_disabled_color"); int side_margin = get_theme_constant("side_margin"); // Find out start and width of the header area. @@ -433,17 +433,17 @@ void TabContainer::_notification(int p_what) { int tab_width = tab_widths[i]; if (get_tab_disabled(index)) { if (rtl) { - _draw_tab(tab_disabled, font_color_disabled, index, size.width - (tabs_ofs_cache + x) - tab_width); + _draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width); } else { - _draw_tab(tab_disabled, font_color_disabled, index, tabs_ofs_cache + x); + _draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x); } } else if (index == current) { x_current = x; } else { if (rtl) { - _draw_tab(tab_bg, font_color_bg, index, size.width - (tabs_ofs_cache + x) - tab_width); + _draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width); } else { - _draw_tab(tab_bg, font_color_bg, index, tabs_ofs_cache + x); + _draw_tab(tab_unselected, font_unselected_color, index, tabs_ofs_cache + x); } } @@ -459,9 +459,9 @@ void TabContainer::_notification(int p_what) { // Draw selected tab in front. only draw selected tab when it's in visible range. if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) { if (rtl) { - _draw_tab(tab_fg, font_color_fg, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]); + _draw_tab(tab_selected, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]); } else { - _draw_tab(tab_fg, font_color_fg, current, tabs_ofs_cache + x_current); + _draw_tab(tab_selected, font_selected_color, current, tabs_ofs_cache + x_current); } } @@ -535,6 +535,8 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in Vector<Control *> tabs = _get_tabs(); RID canvas = get_canvas_item(); Ref<Font> font = get_theme_font("font"); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); int icon_text_distance = get_theme_constant("icon_separation"); int tab_width = _get_tab_width(p_index); int header_height = _get_top_margin(); @@ -547,8 +549,8 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in Control *control = Object::cast_to<Control>(tabs[p_index]); 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 x_content = tab_rect.position.x + p_tab_style->get_margin(SIDE_LEFT); + int top_margin = p_tab_style->get_margin(SIDE_TOP); int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2; // Draw the tab icon. @@ -565,6 +567,9 @@ void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, in // Draw the tab text. Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2); + if (outline_size > 0 && font_outline_color.a > 0) { + text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color); + } text_buf[p_index]->draw(canvas, text_pos, p_font_color); } @@ -607,14 +612,14 @@ void TabContainer::_repaint() { Control *c = tabs[i]; if (i == current) { c->show(); - c->set_anchors_and_margins_preset(Control::PRESET_WIDE); + c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); if (tabs_visible) { - c->set_margin(MARGIN_TOP, _get_top_margin()); + c->set_offset(SIDE_TOP, _get_top_margin()); } - c->set_margin(Margin(MARGIN_TOP), c->get_margin(Margin(MARGIN_TOP)) + sb->get_margin(Margin(MARGIN_TOP))); - c->set_margin(Margin(MARGIN_LEFT), c->get_margin(Margin(MARGIN_LEFT)) + sb->get_margin(Margin(MARGIN_LEFT))); - c->set_margin(Margin(MARGIN_RIGHT), c->get_margin(Margin(MARGIN_RIGHT)) - sb->get_margin(Margin(MARGIN_RIGHT))); - c->set_margin(Margin(MARGIN_BOTTOM), c->get_margin(Margin(MARGIN_BOTTOM)) - sb->get_margin(Margin(MARGIN_BOTTOM))); + c->set_offset(Side(SIDE_TOP), c->get_offset(Side(SIDE_TOP)) + sb->get_margin(Side(SIDE_TOP))); + c->set_offset(Side(SIDE_LEFT), c->get_offset(Side(SIDE_LEFT)) + sb->get_margin(Side(SIDE_LEFT))); + c->set_offset(Side(SIDE_RIGHT), c->get_offset(Side(SIDE_RIGHT)) - sb->get_margin(Side(SIDE_RIGHT))); + c->set_offset(Side(SIDE_BOTTOM), c->get_offset(Side(SIDE_BOTTOM)) - sb->get_margin(Side(SIDE_BOTTOM))); } else { c->hide(); @@ -640,7 +645,7 @@ int TabContainer::_get_tab_width(int p_index) const { // Get the width of the text displayed on the tab. Ref<Font> font = get_theme_font("font"); int font_size = get_theme_font_size("font_size"); - String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(control->get_name()); + String text = control->has_meta("_tab_name") ? String(tr(String(control->get_meta("_tab_name")))) : String(tr(control->get_name())); int width = font->get_string_size(text, font_size).width; // Add space for a tab icon. @@ -655,15 +660,15 @@ int TabContainer::_get_tab_width(int p_index) const { } // Respect a minimum size. - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); if (get_tab_disabled(p_index)) { width += tab_disabled->get_minimum_size().width; } else if (p_index == current) { - width += tab_fg->get_minimum_size().width; + width += tab_selected->get_minimum_size().width; } else { - width += tab_bg->get_minimum_size().width; + width += tab_unselected->get_minimum_size().width; } return width; @@ -712,15 +717,15 @@ void TabContainer::add_child_notify(Node *p_child) { current = 0; previous = 0; } - c->set_anchors_and_margins_preset(Control::PRESET_WIDE); + c->set_anchors_and_offsets_preset(Control::PRESET_WIDE); if (tabs_visible) { - c->set_margin(MARGIN_TOP, _get_top_margin()); + c->set_offset(SIDE_TOP, _get_top_margin()); } Ref<StyleBox> sb = get_theme_stylebox("panel"); - c->set_margin(Margin(MARGIN_TOP), c->get_margin(Margin(MARGIN_TOP)) + sb->get_margin(Margin(MARGIN_TOP))); - c->set_margin(Margin(MARGIN_LEFT), c->get_margin(Margin(MARGIN_LEFT)) + sb->get_margin(Margin(MARGIN_LEFT))); - c->set_margin(Margin(MARGIN_RIGHT), c->get_margin(Margin(MARGIN_RIGHT)) - sb->get_margin(Margin(MARGIN_RIGHT))); - c->set_margin(Margin(MARGIN_BOTTOM), c->get_margin(Margin(MARGIN_BOTTOM)) - sb->get_margin(Margin(MARGIN_BOTTOM))); + c->set_offset(Side(SIDE_TOP), c->get_offset(Side(SIDE_TOP)) + sb->get_margin(Side(SIDE_TOP))); + c->set_offset(Side(SIDE_LEFT), c->get_offset(Side(SIDE_LEFT)) + sb->get_margin(Side(SIDE_LEFT))); + c->set_offset(Side(SIDE_RIGHT), c->get_offset(Side(SIDE_RIGHT)) - sb->get_margin(Side(SIDE_RIGHT))); + c->set_offset(Side(SIDE_BOTTOM), c->get_offset(Side(SIDE_BOTTOM)) - sb->get_margin(Side(SIDE_BOTTOM))); update(); p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback)); if (first && is_inside_tree()) { @@ -747,8 +752,6 @@ void TabContainer::set_current_tab(int p_current) { _repaint(); - _change_notify("current_tab"); - if (pending_previous == current) { emit_signal("tab_selected", current); } else { @@ -789,6 +792,10 @@ Control *TabContainer::get_current_tab_control() const { void TabContainer::remove_child_notify(Node *p_child) { Container::remove_child_notify(p_child); + if (!Object::cast_to<Control>(p_child)) { + return; + } + call_deferred("_update_current_tab"); p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback)); @@ -963,8 +970,6 @@ void TabContainer::set_tab_align(TabAlign p_align) { ERR_FAIL_INDEX(p_align, 3); align = p_align; update(); - - _change_notify("tab_align"); } TabContainer::TabAlign TabContainer::get_tab_align() const { @@ -982,9 +987,9 @@ void TabContainer::set_tabs_visible(bool p_visible) { for (int i = 0; i < tabs.size(); i++) { Control *c = tabs[i]; if (p_visible) { - c->set_margin(MARGIN_TOP, _get_top_margin()); + c->set_offset(SIDE_TOP, _get_top_margin()); } else { - c->set_margin(MARGIN_TOP, 0); + c->set_offset(SIDE_TOP, 0); } } @@ -1018,6 +1023,7 @@ void TabContainer::set_tab_title(int p_tab, const String &p_title) { Control *child = _get_tab(p_tab); ERR_FAIL_COND(!child); child->set_meta("_tab_name", p_title); + _refresh_texts(); update(); } @@ -1127,13 +1133,13 @@ Size2 TabContainer::get_minimum_size() const { ms.y = MAX(ms.y, cms.y); } - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); Ref<Font> font = get_theme_font("font"); if (tabs_visible) { - ms.y += MAX(MAX(tab_bg->get_minimum_size().y, tab_fg->get_minimum_size().y), tab_disabled->get_minimum_size().y); + ms.y += MAX(MAX(tab_unselected->get_minimum_size().y, tab_selected->get_minimum_size().y), tab_disabled->get_minimum_size().y); ms.y += _get_top_margin(); } @@ -1239,20 +1245,5 @@ void TabContainer::_bind_methods() { } TabContainer::TabContainer() { - first_tab_cache = 0; - last_tab_cache = 0; - buttons_visible_cache = false; - menu_hovered = false; - highlight_arrow = -1; - tabs_ofs_cache = 0; - current = 0; - previous = 0; - align = ALIGN_CENTER; - tabs_visible = true; - all_tabs_in_front = false; - drag_to_rearrange_enabled = false; - tabs_rearrange_group = -1; - use_hidden_tabs_for_min_size = false; - connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited)); } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 9ff56afe6e..4ed5255729 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,23 +46,23 @@ public: }; private: - int first_tab_cache; - int tabs_ofs_cache; - int last_tab_cache; - int current; - int previous; - bool tabs_visible; - bool all_tabs_in_front; - bool buttons_visible_cache; - bool menu_hovered; - int highlight_arrow; - TabAlign align; + int first_tab_cache = 0; + int tabs_ofs_cache = 0; + int last_tab_cache = 0; + int current = 0; + int previous = 0; + bool tabs_visible = true; + bool all_tabs_in_front = false; + bool buttons_visible_cache = false; + bool menu_hovered = false; + int highlight_arrow = -1; + TabAlign align = ALIGN_CENTER; Control *_get_tab(int p_idx) const; int _get_top_margin() const; mutable ObjectID popup_obj_id; - bool drag_to_rearrange_enabled; - bool use_hidden_tabs_for_min_size; - int tabs_rearrange_group; + bool drag_to_rearrange_enabled = false; + bool use_hidden_tabs_for_min_size = false; + int tabs_rearrange_group = -1; Vector<Ref<TextLine>> text_buf; Vector<Control *> _get_tabs() const; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 5b26428e45..38a5588b7e 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,11 +38,11 @@ #include "scene/gui/texture_rect.h" Size2 Tabs::get_minimum_size() const { - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); - int y_margin = MAX(MAX(tab_bg->get_minimum_size().height, tab_fg->get_minimum_size().height), tab_disabled->get_minimum_size().height); + int y_margin = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height); Size2 ms(0, 0); @@ -61,9 +61,9 @@ Size2 Tabs::get_minimum_size() const { if (tabs[i].disabled) { ms.width += tab_disabled->get_minimum_size().width; } else if (current == i) { - ms.width += tab_fg->get_minimum_size().width; + ms.width += tab_selected->get_minimum_size().width; } else { - ms.width += tab_bg->get_minimum_size().width; + ms.width += tab_unselected->get_minimum_size().width; } if (tabs[i].right_button.is_valid()) { @@ -71,7 +71,7 @@ Size2 Tabs::get_minimum_size() const { Size2 bms = rb->get_size(); bms.width += get_theme_constant("hseparation"); ms.width += bms.width; - ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height); + ms.height = MAX(bms.height + tab_unselected->get_minimum_size().height, ms.height); } if (cb_displaypolicy == CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy == CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i == current)) { @@ -79,11 +79,14 @@ Size2 Tabs::get_minimum_size() const { Size2 bms = cb->get_size(); bms.width += get_theme_constant("hseparation"); ms.width += bms.width; - ms.height = MAX(bms.height + tab_bg->get_minimum_size().height, ms.height); + ms.height = MAX(bms.height + tab_unselected->get_minimum_size().height, ms.height); } } - ms.width = 0; //TODO: should make this optional + if (clip_tabs) { + ms.width = 0; + } + return ms; } @@ -105,10 +108,10 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { highlight_arrow = 0; } } else { - int limit = get_size().width - incr->get_width() - decr->get_width(); - if (pos.x > limit + decr->get_width()) { + int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); + if (pos.x > limit_minus_buttons + decr->get_width()) { highlight_arrow = 1; - } else if (pos.x > limit) { + } else if (pos.x > limit_minus_buttons) { highlight_arrow = 0; } } @@ -122,7 +125,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { - if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) { + if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) { if (scrolling_enabled && buttons_visible) { if (offset > 0) { offset--; @@ -131,7 +134,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { } } - if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) { + if (mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) { if (scrolling_enabled && buttons_visible) { if (missing_right) { offset++; @@ -140,7 +143,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { } } - if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (rb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (rb_hover != -1) { //pressed emit_signal("right_button_pressed", rb_hover); @@ -150,7 +153,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { update(); } - if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (cb_pressing && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (cb_hover != -1) { //pressed emit_signal("tab_closed", cb_hover); @@ -160,7 +163,7 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) { update(); } - if (mb->is_pressed() && (mb->get_button_index() == BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == BUTTON_RIGHT))) { + if (mb->is_pressed() && (mb->get_button_index() == MOUSE_BUTTON_LEFT || (select_with_rmb && mb->get_button_index() == MOUSE_BUTTON_RIGHT))) { // clicks Point2 pos(mb->get_position().x, mb->get_position().y); @@ -268,13 +271,16 @@ void Tabs::_notification(int p_what) { _update_cache(); RID ci = get_canvas_item(); - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); - Color color_fg = get_theme_color("font_color_fg"); - Color color_bg = get_theme_color("font_color_bg"); - Color color_disabled = get_theme_color("font_color_disabled"); + Color font_selected_color = get_theme_color("font_selected_color"); + Color font_unselected_color = get_theme_color("font_unselected_color"); + Color font_disabled_color = get_theme_color("font_disabled_color"); Ref<Texture2D> close = get_theme_icon("close"); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); + Vector2 size = get_size(); bool rtl = is_layout_rtl(); @@ -302,7 +308,8 @@ void Tabs::_notification(int p_what) { Ref<Texture2D> incr_hl = get_theme_icon("increment_highlight"); Ref<Texture2D> decr_hl = get_theme_icon("decrement_highlight"); - int limit = get_size().width - incr->get_size().width - decr->get_size().width; + int limit = get_size().width; + int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); missing_right = false; @@ -316,16 +323,17 @@ void Tabs::_notification(int p_what) { if (tabs[i].disabled) { sb = tab_disabled; - col = color_disabled; + col = font_disabled_color; } else if (i == current) { - sb = tab_fg; - col = color_fg; + sb = tab_selected; + col = font_selected_color; } else { - sb = tab_bg; - col = color_bg; + sb = tab_unselected; + col = font_unselected_color; } - if (w + lsize > limit) { + int new_width = w + lsize; + if (new_width > limit || (i < tabs.size() - 1 && new_width > limit_minus_buttons)) { // For the last tab, we accept if the tab covers the buttons. max_drawn_tab = i - 1; missing_right = true; break; @@ -341,15 +349,15 @@ void Tabs::_notification(int p_what) { } sb->draw(ci, sb_rect); - w += sb->get_margin(MARGIN_LEFT); + w += sb->get_margin(SIDE_LEFT); Size2i sb_ms = sb->get_minimum_size(); Ref<Texture2D> icon = tabs[i].icon; if (icon.is_valid()) { if (rtl) { - icon->draw(ci, Point2i(size.width - w - icon->get_width(), sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); + icon->draw(ci, Point2i(size.width - w - icon->get_width(), sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); } else { - icon->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); + icon->draw(ci, Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - icon->get_height()) / 2)); } if (tabs[i].text != "") { w += icon->get_width() + get_theme_constant("hseparation"); @@ -357,9 +365,17 @@ void Tabs::_notification(int p_what) { } if (rtl) { - tabs[i].text_buf->draw(ci, Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col); + Vector2 text_pos = Point2i(size.width - w - tabs[i].text_buf->get_size().x, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2); + if (outline_size > 0 && font_outline_color.a > 0) { + tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + tabs[i].text_buf->draw(ci, text_pos, col); } else { - tabs[i].text_buf->draw(ci, Point2i(w, sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2), col); + Vector2 text_pos = Point2i(w, sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - tabs[i].text_buf->get_size().y) / 2); + if (outline_size > 0 && font_outline_color.a > 0) { + tabs[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + tabs[i].text_buf->draw(ci, text_pos, col); } w += tabs[i].size_text; @@ -377,7 +393,7 @@ void Tabs::_notification(int p_what) { } else { rb_rect.position.x = w; } - rb_rect.position.y = sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - (rb_rect.size.y)) / 2; + rb_rect.position.y = sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - (rb_rect.size.y)) / 2; if (rb_hover == i) { if (rb_pressing) { @@ -388,9 +404,9 @@ void Tabs::_notification(int p_what) { } if (rtl) { - rb->draw(ci, Point2i(size.width - w - rb_rect.size.x + style->get_margin(MARGIN_LEFT), rb_rect.position.y + style->get_margin(MARGIN_TOP))); + rb->draw(ci, Point2i(size.width - w - rb_rect.size.x + style->get_margin(SIDE_LEFT), rb_rect.position.y + style->get_margin(SIDE_TOP))); } else { - rb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), rb_rect.position.y + style->get_margin(MARGIN_TOP))); + rb->draw(ci, Point2i(w + style->get_margin(SIDE_LEFT), rb_rect.position.y + style->get_margin(SIDE_TOP))); } w += rb->get_width(); tabs.write[i].rb_rect = rb_rect; @@ -409,7 +425,7 @@ void Tabs::_notification(int p_what) { } else { cb_rect.position.x = w; } - cb_rect.position.y = sb->get_margin(MARGIN_TOP) + ((sb_rect.size.y - sb_ms.y) - (cb_rect.size.y)) / 2; + cb_rect.position.y = sb->get_margin(SIDE_TOP) + ((sb_rect.size.y - sb_ms.y) - (cb_rect.size.y)) / 2; if (!tabs[i].disabled && cb_hover == i) { if (cb_pressing) { @@ -420,15 +436,15 @@ void Tabs::_notification(int p_what) { } if (rtl) { - cb->draw(ci, Point2i(size.width - w - cb_rect.size.x + style->get_margin(MARGIN_LEFT), cb_rect.position.y + style->get_margin(MARGIN_TOP))); + cb->draw(ci, Point2i(size.width - w - cb_rect.size.x + style->get_margin(SIDE_LEFT), cb_rect.position.y + style->get_margin(SIDE_TOP))); } else { - cb->draw(ci, Point2i(w + style->get_margin(MARGIN_LEFT), cb_rect.position.y + style->get_margin(MARGIN_TOP))); + cb->draw(ci, Point2i(w + style->get_margin(SIDE_LEFT), cb_rect.position.y + style->get_margin(SIDE_TOP))); } w += cb->get_width(); tabs.write[i].cb_rect = cb_rect; } - w += sb->get_margin(MARGIN_RIGHT); + w += sb->get_margin(SIDE_RIGHT); } if (offset > 0 || missing_right) { @@ -448,15 +464,15 @@ void Tabs::_notification(int p_what) { } } else { if (offset > 0) { - draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit, vofs)); + draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs)); } else { - draw_texture(decr, Point2(limit, vofs), Color(1, 1, 1, 0.5)); + draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5)); } if (missing_right) { - draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit + decr->get_size().width, vofs)); + draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs)); } else { - draw_texture(incr, Point2(limit + decr->get_size().width, vofs), Color(1, 1, 1, 0.5)); + draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5)); } } @@ -481,7 +497,6 @@ void Tabs::set_current_tab(int p_current) { previous = current; current = p_current; - _change_notify("current_tab"); _update_cache(); update(); @@ -652,11 +667,11 @@ void Tabs::_update_hover() { void Tabs::_update_cache() { Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<Texture2D> incr = get_theme_icon("increment"); Ref<Texture2D> decr = get_theme_icon("decrement"); - int limit = get_size().width - incr->get_width() - decr->get_width(); + int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); int w = 0; int mw = 0; @@ -676,22 +691,22 @@ void Tabs::_update_cache() { } int m_width = min_width; if (count_resize > 0) { - m_width = MAX((limit - size_fixed) / count_resize, min_width); + m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width); } for (int i = offset; i < tabs.size(); i++) { Ref<StyleBox> sb; if (tabs[i].disabled) { sb = tab_disabled; } else if (i == current) { - sb = tab_fg; + sb = tab_selected; } else { - sb = tab_bg; + sb = tab_unselected; } int lsize = tabs[i].size_cache; int slen = tabs[i].size_text; - if (min_width > 0 && mw > limit && i != current) { + if (min_width > 0 && mw > limit_minus_buttons && i != current) { if (lsize > m_width) { - slen = m_width - (sb->get_margin(MARGIN_LEFT) + sb->get_margin(MARGIN_RIGHT)); + slen = m_width - (sb->get_margin(SIDE_LEFT) + sb->get_margin(SIDE_RIGHT)); if (tabs[i].icon.is_valid()) { slen -= tabs[i].icon->get_width(); slen -= get_theme_constant("hseparation"); @@ -899,6 +914,19 @@ Tabs::TabAlign Tabs::get_tab_align() const { return tab_align; } +void Tabs::set_clip_tabs(bool p_clip_tabs) { + if (clip_tabs == p_clip_tabs) { + return; + } + clip_tabs = p_clip_tabs; + update(); + minimum_size_changed(); +} + +bool Tabs::get_clip_tabs() const { + return clip_tabs; +} + void Tabs::move_tab(int from, int to) { if (from == to) { return; @@ -918,8 +946,8 @@ void Tabs::move_tab(int from, int to) { int Tabs::get_tab_width(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, tabs.size(), 0); - Ref<StyleBox> tab_bg = get_theme_stylebox("tab_bg"); - Ref<StyleBox> tab_fg = get_theme_stylebox("tab_fg"); + Ref<StyleBox> tab_unselected = get_theme_stylebox("tab_unselected"); + Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected"); Ref<StyleBox> tab_disabled = get_theme_stylebox("tab_disabled"); int x = 0; @@ -937,9 +965,9 @@ int Tabs::get_tab_width(int p_idx) const { if (tabs[p_idx].disabled) { x += tab_disabled->get_minimum_size().width; } else if (current == p_idx) { - x += tab_fg->get_minimum_size().width; + x += tab_selected->get_minimum_size().width; } else { - x += tab_bg->get_minimum_size().width; + x += tab_unselected->get_minimum_size().width; } if (tabs[p_idx].right_button.is_valid()) { @@ -965,7 +993,8 @@ void Tabs::_ensure_no_over_offset() { Ref<Texture2D> incr = get_theme_icon("increment"); Ref<Texture2D> decr = get_theme_icon("decrement"); - int limit = get_size().width - incr->get_width() - decr->get_width(); + int limit = get_size().width; + int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); while (offset > 0) { int total_w = 0; @@ -973,7 +1002,7 @@ void Tabs::_ensure_no_over_offset() { total_w += tabs[i].size_cache; } - if (total_w < limit) { + if ((buttons_visible && total_w < limit_minus_buttons) || total_w < limit) { // For the last tab, we accept if the tab covers the buttons. offset--; update(); } else { @@ -1004,9 +1033,12 @@ void Tabs::ensure_tab_visible(int p_idx) { int prev_offset = offset; Ref<Texture2D> incr = get_theme_icon("increment"); Ref<Texture2D> decr = get_theme_icon("decrement"); - int limit = get_size().width - incr->get_width() - decr->get_width(); + int limit = get_size().width; + int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width(); + for (int i = offset; i <= p_idx; i++) { - if (tabs[i].ofs_cache + tabs[i].size_cache > limit) { + int total_w = tabs[i].ofs_cache + tabs[i].size_cache; + if (total_w > limit || (buttons_visible && total_w > limit_minus_buttons)) { offset++; } } @@ -1095,6 +1127,8 @@ void Tabs::_bind_methods() { ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &Tabs::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>())); ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align); ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align); + ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &Tabs::set_clip_tabs); + ClassDB::bind_method(D_METHOD("get_clip_tabs"), &Tabs::get_clip_tabs); ClassDB::bind_method(D_METHOD("get_tab_offset"), &Tabs::get_tab_offset); ClassDB::bind_method(D_METHOD("get_offset_buttons_visible"), &Tabs::get_offset_buttons_visible); ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible); @@ -1121,6 +1155,7 @@ void Tabs::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs"); ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled"); @@ -1137,27 +1172,5 @@ void Tabs::_bind_methods() { } Tabs::Tabs() { - current = 0; - previous = 0; - tab_align = ALIGN_CENTER; - rb_hover = -1; - rb_pressing = false; - highlight_arrow = -1; - - cb_hover = -1; - cb_pressing = false; - cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; - offset = 0; - max_drawn_tab = 0; - - select_with_rmb = false; - - min_width = 0; - scrolling_enabled = true; - buttons_visible = false; - hover = -1; - drag_to_rearrange_enabled = false; - tabs_rearrange_group = -1; - connect("mouse_exited", callable_mp(this, &Tabs::_on_mouse_exited)); } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index bf62ba7210..61c9a5d96a 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -63,42 +63,43 @@ private: Ref<TextLine> text_buf; Ref<Texture2D> icon; - int ofs_cache; - bool disabled; - int size_cache; - int size_text; - int x_cache; - int x_size_cache; + int ofs_cache = 0; + bool disabled = false; + int size_cache = 0; + int size_text = 0; + int x_cache = 0; + int x_size_cache = 0; Ref<Texture2D> right_button; Rect2 rb_rect; Rect2 cb_rect; }; - int offset; - int max_drawn_tab; - int highlight_arrow; - bool buttons_visible; - bool missing_right; + int offset = 0; + int max_drawn_tab = 0; + int highlight_arrow = -1; + bool buttons_visible = false; + bool missing_right = false; Vector<Tab> tabs; - int current; - int previous; + int current = 0; + int previous = 0; int _get_top_margin() const; - TabAlign tab_align; - int rb_hover; - bool rb_pressing; + TabAlign tab_align = ALIGN_CENTER; + bool clip_tabs = true; + int rb_hover = -1; + bool rb_pressing = false; - bool select_with_rmb; + bool select_with_rmb = false; - int cb_hover; - bool cb_pressing; - CloseButtonDisplayPolicy cb_displaypolicy; + int cb_hover = -1; + bool cb_pressing = false; + CloseButtonDisplayPolicy cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; - int hover; // Hovered tab. - int min_width; - bool scrolling_enabled; - bool drag_to_rearrange_enabled; - int tabs_rearrange_group; + int hover = -1; // Hovered tab. + int min_width = 0; + bool scrolling_enabled = true; + bool drag_to_rearrange_enabled = false; + int tabs_rearrange_group = -1; int get_tab_width(int p_idx) const; void _ensure_no_over_offset(); @@ -148,6 +149,9 @@ public: void set_tab_align(TabAlign p_align); TabAlign get_tab_align() const; + void set_clip_tabs(bool p_clip_tabs); + bool get_clip_tabs() const; + void move_tab(int from, int to); void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index bf7e82e87c..74c530f1b0 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/input/input.h" +#include "core/input/input_map.h" #include "core/object/message_queue.h" #include "core/object/script_language.h" #include "core/os/keyboard.h" @@ -189,12 +190,12 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ text.write[p_line].data_buf->set_preserve_control(draw_control_chars); if (p_ime_text.length() > 0) { text.write[p_line].data_buf->add_string(p_ime_text, font, font_size, opentype_features, language); - if (!p_bidi_override.empty()) { + if (!p_bidi_override.is_empty()) { TS->shaped_text_set_bidi_override(text.write[p_line].data_buf->get_rid(), p_bidi_override); } } else { text.write[p_line].data_buf->add_string(text[p_line].data, font, font_size, opentype_features, language); - if (!text[p_line].bidi_override.empty()) { + if (!text[p_line].bidi_override.is_empty()) { TS->shaped_text_set_bidi_override(text.write[p_line].data_buf->get_rid(), text[p_line].bidi_override); } } @@ -202,7 +203,7 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ // Apply tab align. if (indent_size > 0) { Vector<float> tabs; - tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size); + tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size); text.write[p_line].data_buf->tab_align(tabs); } } @@ -212,7 +213,7 @@ void TextEdit::Text::invalidate_all_lines() { text.write[i].data_buf->set_width(width); if (indent_size > 0) { Vector<float> tabs; - tabs.push_back(font->get_char_size('m', 0, font_size).width * indent_size); + tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size); text.write[i].data_buf->tab_align(tabs); } } @@ -296,8 +297,8 @@ void TextEdit::_update_scrollbars() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - v_scroll->set_begin(Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP))); - v_scroll->set_end(Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM))); + v_scroll->set_begin(Point2(size.width - vmin.width, cache.style_normal->get_margin(SIDE_TOP))); + v_scroll->set_end(Point2(size.width, size.height - cache.style_normal->get_margin(SIDE_TOP) - cache.style_normal->get_margin(SIDE_BOTTOM))); h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); @@ -356,10 +357,10 @@ void TextEdit::_update_scrollbars() { } 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 + // Warning: is_mouse_button_pressed(MOUSE_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 != SelectionMode::SELECTION_MODE_NONE) { + if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT) && selection.selecting_mode != SelectionMode::SELECTION_MODE_NONE) { switch (selection.selecting_mode) { case SelectionMode::SELECTION_MODE_POINTER: { _update_selection_mode_pointer(); @@ -411,25 +412,16 @@ void TextEdit::_update_selection_mode_word() { _get_mouse_pos(Point2i(mp.x, mp.y), row, col); String line = text[row]; - int beg = CLAMP(col, 0, line.length()); - // If its the first selection and on whitespace make sure we grab the word instead. - if (!selection.active) { - while (beg > 0 && line[beg] <= 32) { - beg--; - } - } + int cursor_pos = CLAMP(col, 0, line.length()); + int beg = cursor_pos; int end = beg; - bool symbol = beg < line.length() && _is_symbol(line[beg]); - - // Get the word end and begin points. - while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) { - beg--; - } - while (end < line.length() && line[end + 1] > 32 && (symbol == _is_symbol(line[end + 1]))) { - end++; - } - if (end < line.length()) { - end += 1; + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(row)->get_rid()); + for (int i = 0; i < words.size(); i++) { + if (words[i].x < cursor_pos && words[i].y > cursor_pos) { + beg = words[i].x; + end = words[i].y; + break; + } } // Initial selection. @@ -489,7 +481,7 @@ void TextEdit::_update_selection_mode_line() { void TextEdit::_update_minimap_click() { Point2 mp = _get_local_mouse_pos(); - int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); + int xmargin_end = get_size().width - cache.style_normal->get_margin(SIDE_RIGHT); if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) { minimap_clicked = false; return; @@ -500,7 +492,7 @@ void TextEdit::_update_minimap_click() { int row; _get_minimap_mouse_row(Point2i(mp.x, mp.y), row); - if (row >= get_first_visible_line() && (row < get_last_visible_line() || row >= (text.size() - 1))) { + if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) { minimap_scroll_ratio = v_scroll->get_as_ratio(); minimap_scroll_click_pos = mp.y; can_drag_minimap = true; @@ -622,9 +614,9 @@ void TextEdit::_notification(int p_what) { 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) + gutters_width + gutter_padding; + int xmargin_beg = cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding; - int xmargin_end = size.width - cache.style_normal->get_margin(MARGIN_RIGHT) - cache.minimap_width; + int xmargin_end = size.width - cache.style_normal->get_margin(SIDE_RIGHT) - cache.minimap_width; // Let's do it easy for now. cache.style_normal->draw(ci, Rect2(Point2(), size)); if (readonly) { @@ -637,7 +629,7 @@ void TextEdit::_notification(int p_what) { int visible_rows = get_visible_rows() + 1; - Color color = readonly ? cache.font_color_readonly : cache.font_color; + Color color = readonly ? cache.font_readonly_color : cache.font_color; if (cache.background_color.a > 0.01) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), cache.background_color); @@ -810,13 +802,13 @@ void TextEdit::_notification(int p_what) { } } + bool is_cursor_line_visible = false; Point2 cursor_pos; - int cursor_insert_offset_y = 0; // Get the highlighted words. String highlighted_text = get_selection_text(); - // Check if highlighted words contains only whitespaces (tabs or spaces). + // Check if highlighted words contain only whitespaces (tabs or spaces). bool only_whitespaces_highlighted = highlighted_text.strip_edges() == String(); int cursor_wrap_index = get_cursor_wrap_index(); @@ -877,7 +869,7 @@ void TextEdit::_notification(int p_what) { Color current_color = cache.font_color; if (readonly) { - current_color = cache.font_color_readonly; + current_color = cache.font_readonly_color; } Vector<String> wrap_rows = get_wrap_rows_text(minimap_line); @@ -918,7 +910,7 @@ void TextEdit::_notification(int p_what) { if (color_map.has(last_wrap_column + j)) { current_color = color_map[last_wrap_column + j].get("color"); if (readonly) { - current_color.a = cache.font_color_readonly.a; + current_color.a = cache.font_readonly_color.a; } } color = current_color; @@ -977,6 +969,16 @@ void TextEdit::_notification(int p_what) { } } + int top_limit_y = 0; + int bottom_limit_y = get_size().height; + if (readonly) { + top_limit_y += cache.style_readonly->get_margin(SIDE_TOP); + bottom_limit_y -= cache.style_readonly->get_margin(SIDE_BOTTOM); + } else { + top_limit_y += cache.style_normal->get_margin(SIDE_TOP); + bottom_limit_y -= cache.style_normal->get_margin(SIDE_BOTTOM); + } + // draw main text int row_height = get_row_height(); int line = first_visible_line; @@ -1001,7 +1003,7 @@ void TextEdit::_notification(int p_what) { Dictionary color_map = _get_line_syntax_highlighting(line); // Ensure we at least use the font color. - Color current_color = readonly ? cache.font_color_readonly : cache.font_color; + Color current_color = readonly ? cache.font_readonly_color : cache.font_color; const Ref<TextParagraph> ldata = text.get_line_data(line); @@ -1019,17 +1021,33 @@ void TextEdit::_notification(int p_what) { const String &str = wrap_rows[line_wrap_index]; int char_margin = xmargin_beg - cursor.x_ofs; - int ofs_readonly = 0; int ofs_x = 0; + int ofs_y = 0; if (readonly) { - ofs_readonly = cache.style_readonly->get_offset().y / 2; ofs_x = cache.style_readonly->get_offset().x / 2; + ofs_x -= cache.style_normal->get_offset().x / 2; + ofs_y = cache.style_readonly->get_offset().y / 2; + } else { + ofs_y = cache.style_normal->get_offset().y / 2; } - int ofs_y = (i * row_height + cache.line_spacing / 2) + ofs_readonly; + ofs_y += i * row_height + cache.line_spacing / 2; ofs_y -= cursor.wrap_ofs * row_height; ofs_y -= get_v_scroll_offset() * row_height; + bool clipped = false; + if (ofs_y + row_height < top_limit_y) { + // Line is outside the top margin, clip current line. + // Still need to go through the process to prepare color changes for next lines. + clipped = true; + } + + if (ofs_y > bottom_limit_y) { + // Line is outside the bottom margin, clip any remaining text. + i = draw_amount; + break; + } + if (text.is_marked(line)) { if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), cache.mark_color); @@ -1039,7 +1057,7 @@ void TextEdit::_notification(int p_what) { } if (str.length() == 0) { - // Draw line background if empty as we won't loop at at all. + // Draw line background if empty as we won't loop at all. if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) { if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), cache.current_line_color); @@ -1050,7 +1068,7 @@ void TextEdit::_notification(int p_what) { // Give visual indication of empty selected line. if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) { - int char_w = cache.font->get_char_size('m', 0, cache.font_size).width; + int char_w = cache.font->get_char_size(' ', 0, cache.font_size).width; if (rtl) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - xmargin_beg - ofs_x - char_w, ofs_y, char_w, row_height), cache.selection_color); } else { @@ -1071,7 +1089,7 @@ 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. - int gutter_offset = cache.style_normal->get_margin(MARGIN_LEFT); + int gutter_offset = cache.style_normal->get_margin(SIDE_LEFT); for (int g = 0; g < gutters.size(); g++) { const GutterInfo gutter = gutters[g]; @@ -1091,6 +1109,9 @@ void TextEdit::_notification(int p_what) { tl->add_string(text, cache.font, cache.font_size); int yofs = ofs_y + (row_height - tl->get_size().y) / 2; + if (cache.outline_size > 0 && cache.outline_color.a > 0) { + tl->draw_outline(ci, Point2(gutter_offset + ofs_x, yofs), cache.outline_size, cache.outline_color); + } tl->draw(ci, Point2(gutter_offset + ofs_x, yofs), get_line_gutter_item_color(line, g)); } break; case GUTTER_TPYE_ICON: { @@ -1147,7 +1168,7 @@ void TextEdit::_notification(int p_what) { char_margin = size.width - char_margin - TS->shaped_text_get_size(rid).x; } - if (selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection + if (!clipped && selection.active && line >= selection.from_line && line <= selection.to_line) { // Selection int sel_from = (line > selection.from_line) ? TS->shaped_text_get_range(rid).x : selection.from_column; int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column; Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to); @@ -1167,7 +1188,7 @@ void TextEdit::_notification(int p_what) { } int start = TS->shaped_text_get_range(rid).x; - if (!search_text.empty()) { // Search highhlight + if (!clipped && !search_text.is_empty()) { // Search highhlight int search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0); while (search_text_col != -1) { Vector<Vector2> sel = TS->shaped_text_get_selection(rid, search_text_col + start, search_text_col + search_text.length() + start); @@ -1190,7 +1211,7 @@ void TextEdit::_notification(int p_what) { } } - if (highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.empty()) { // Highlight + if (!clipped && highlight_all_occurrences && !only_whitespaces_highlighted && !highlighted_text.is_empty()) { // Highlight int highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); while (highlighted_text_col != -1) { Vector<Vector2> sel = TS->shaped_text_get_selection(rid, highlighted_text_col + start, highlighted_text_col + highlighted_text.length() + start); @@ -1212,7 +1233,7 @@ void TextEdit::_notification(int p_what) { } } - if (select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word + if (!clipped && select_identifiers_enabled && highlighted_word.length() != 0) { // Highlight word if (_is_char(highlighted_word[0]) || highlighted_word[0] == '.') { int highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0); while (highlighted_word_col != -1) { @@ -1230,7 +1251,7 @@ void TextEdit::_notification(int p_what) { } rect.position.y = TS->shaped_text_get_ascent(rid) + cache.font->get_underline_position(cache.font_size); rect.size.y = cache.font->get_underline_thickness(cache.font_size); - draw_rect(rect, cache.font_color_selected); + draw_rect(rect, cache.font_selected_color); } highlighted_word_col = _get_column_pos_of_word(highlighted_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, highlighted_word_col + 1); @@ -1238,6 +1259,7 @@ void TextEdit::_notification(int p_what) { } } + const int line_top_offset_y = ofs_y; ofs_y += (row_height - text_height) / 2; const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(rid); @@ -1246,11 +1268,27 @@ void TextEdit::_notification(int p_what) { ofs_y += ldata->get_line_ascent(line_wrap_index); int char_ofs = 0; + if (cache.outline_size > 0 && cache.outline_color.a > 0) { + for (int j = 0; j < gl_size; j++) { + for (int k = 0; k < glyphs[j].repeat; k++) { + if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { + if (glyphs[j].font_rid != RID()) { + TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, cache.outline_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, cache.outline_color); + } + } + char_ofs += glyphs[j].advance; + } + if ((char_ofs + char_margin) >= xmargin_end) { + break; + } + } + char_ofs = 0; + } for (int j = 0; j < gl_size; j++) { if (color_map.has(glyphs[j].start)) { current_color = color_map[glyphs[j].start].get("color"); - if (readonly && current_color.a > cache.font_color_readonly.a) { - current_color.a = cache.font_color_readonly.a; + if (readonly && current_color.a > cache.font_readonly_color.a) { + current_color.a = cache.font_readonly_color.a; } } @@ -1259,40 +1297,44 @@ void TextEdit::_notification(int p_what) { int sel_to = (line < selection.to_line) ? TS->shaped_text_get_range(rid).y : selection.to_column; if (glyphs[j].start >= sel_from && glyphs[j].end <= sel_to && override_selected_font_color) { - current_color = cache.font_color_selected; + current_color = cache.font_selected_color; } } - if (brace_matching_enabled) { - if ((brace_open_match_line == line && brace_open_match_column == glyphs[j].start) || - (cursor.column == glyphs[j].start && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) { - if (brace_open_mismatch) { - current_color = cache.brace_mismatch_color; + int char_pos = char_ofs + char_margin + ofs_x; + if (char_pos >= xmargin_beg) { + if (brace_matching_enabled) { + if ((brace_open_match_line == line && brace_open_match_column == glyphs[j].start) || + (cursor.column == glyphs[j].start && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) { + if (brace_open_mismatch) { + current_color = cache.brace_mismatch_color; + } + Rect2 rect = Rect2(char_pos, ofs_y + cache.font->get_underline_position(cache.font_size), glyphs[j].advance * glyphs[j].repeat, cache.font->get_underline_thickness(cache.font_size)); + draw_rect(rect, current_color); } - Rect2 rect = Rect2(char_ofs + char_margin + ofs_x, ofs_y + cache.font->get_underline_position(cache.font_size), glyphs[j].advance * glyphs[j].repeat, cache.font->get_underline_thickness(cache.font_size)); - draw_rect(rect, current_color); - } - if ((brace_close_match_line == line && brace_close_match_column == glyphs[j].start) || - (cursor.column == glyphs[j].start + 1 && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) { - if (brace_close_mismatch) { - current_color = cache.brace_mismatch_color; + if ((brace_close_match_line == line && brace_close_match_column == glyphs[j].start) || + (cursor.column == glyphs[j].start + 1 && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) { + if (brace_close_mismatch) { + current_color = cache.brace_mismatch_color; + } + Rect2 rect = Rect2(char_pos, ofs_y + cache.font->get_underline_position(cache.font_size), glyphs[j].advance * glyphs[j].repeat, cache.font->get_underline_thickness(cache.font_size)); + draw_rect(rect, current_color); } - Rect2 rect = Rect2(char_ofs + char_margin + ofs_x, ofs_y + cache.font->get_underline_position(cache.font_size), glyphs[j].advance * glyphs[j].repeat, cache.font->get_underline_thickness(cache.font_size)); - draw_rect(rect, current_color); + } + + if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) { + int yofs = (text_height - cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); + cache.tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), current_color); + } else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) { + int yofs = (text_height - cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); + int xofs = (glyphs[j].advance * glyphs[j].repeat - cache.space_icon->get_width()) / 2; + cache.space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), current_color); } } - if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) { - int yofs = (text_height - cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); - cache.tab_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), current_color); - } - if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE)) { - int yofs = (text_height - cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); - int xofs = (glyphs[j].advance * glyphs[j].repeat - cache.space_icon->get_width()) / 2; - cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x + xofs, ofs_y + yofs), current_color); - } + for (int k = 0; k < glyphs[j].repeat; k++) { - if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { + if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { if (glyphs[j].font_rid != RID()) { TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, current_color); } else if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { @@ -1307,11 +1349,13 @@ void TextEdit::_notification(int p_what) { } if (line_wrap_index == line_wrap_amount && is_folded(line)) { - int yofs = (text_height - cache.folded_eol_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); - int xofs = cache.folded_eol_icon->get_width() / 2; - Color eol_color = cache.code_folding_color; - eol_color.a = 1; - cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), eol_color); + int xofs = char_ofs + char_margin + ofs_x + (cache.folded_eol_icon->get_width() / 2); + if (xofs >= xmargin_beg && xofs < xmargin_end) { + int yofs = (text_height - cache.folded_eol_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); + Color eol_color = cache.code_folding_color; + eol_color.a = 1; + cache.folded_eol_icon->draw(ci, Point2(xofs, ofs_y + yofs), eol_color); + } } // Carets @@ -1320,8 +1364,10 @@ void TextEdit::_notification(int p_what) { #else int caret_width = 1; #endif - if (cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) { - cursor_pos.y = ofs_y + ldata->get_line_descent(line_wrap_index); + if (!clipped && cursor.line == line && ((line_wrap_index == line_wrap_amount) || (cursor.column != TS->shaped_text_get_range(rid).y))) { + is_cursor_line_visible = true; + cursor_pos.y = line_top_offset_y; + if (ime_text.length() == 0) { Rect2 l_caret, t_caret; TextServer::Direction l_dir, t_dir; @@ -1346,7 +1392,7 @@ void TextEdit::_notification(int p_what) { cursor_pos.x = char_margin + ofs_x + t_caret.position.x; } - if (draw_caret) { + if (draw_caret && cursor_pos.x >= xmargin_beg && cursor_pos.x < xmargin_end) { if (block_caret || insert_mode) { //Block or underline caret, draw trailing carets at full height. int h = cache.font->get_height(cache.font_size); @@ -1371,7 +1417,7 @@ void TextEdit::_notification(int p_what) { l_caret.size.y = h; } l_caret.position += Vector2(char_margin + ofs_x, ofs_y); - l_caret.size.x = cache.font->get_char_size('m', 0, cache.font_size).x; + l_caret.size.x = cache.font->get_char_size('M', 0, cache.font_size).x; draw_rect(l_caret, cache.caret_color, false); } @@ -1396,7 +1442,7 @@ void TextEdit::_notification(int p_what) { } } else { { - // IME intermidiet text range. + // IME Intermediate text range. Vector<Vector2> sel = TS->shaped_text_get_selection(rid, cursor.column, cursor.column + ime_text.length()); for (int j = 0; j < sel.size(); j++) { Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height); @@ -1435,83 +1481,101 @@ void TextEdit::_notification(int p_what) { } } } - ofs_y += ldata->get_line_descent(line_wrap_index); } } bool completion_below = false; - if (completion_active && completion_options.size() > 0) { - // Code completion box. - Ref<StyleBox> csb = get_theme_stylebox("completion"); - int maxlines = get_theme_constant("completion_lines"); - int cmax_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x', 0, cache.font_size).x; - int scrollw = get_theme_constant("completion_scroll_width"); - Color scrollc = get_theme_color("completion_scroll_color"); + if (completion_active && is_cursor_line_visible && completion_options.size() > 0) { + // Completion panel + + const Ref<StyleBox> csb = get_theme_stylebox("completion"); + const int maxlines = get_theme_constant("completion_lines"); + const int cmax_width = get_theme_constant("completion_max_width") * cache.font->get_char_size('x', 0, cache.font_size).x; + const Color scrollc = get_theme_color("completion_scroll_color"); const int completion_options_size = completion_options.size(); - int lines = MIN(completion_options_size, maxlines); - int w = 0; - int h = lines * row_height; - int nofs = cache.font->get_string_size(completion_base, cache.font_size).width; + const int row_count = MIN(completion_options_size, maxlines); + const int completion_rows_height = row_count * row_height; + const int completion_base_width = cache.font->get_string_size(completion_base, cache.font_size).width; + int scroll_rectangle_width = get_theme_constant("completion_scroll_width"); + int width = 0; + + // Compute max width of the panel based on the longest completion option if (completion_options_size < 50) { for (int i = 0; i < completion_options_size; i++) { - int w2 = MIN(cache.font->get_string_size(completion_options[i].display, cache.font_size).x, cmax_width); - if (w2 > w) { - w = w2; + int line_width = MIN(cache.font->get_string_size(completion_options[i].display, cache.font_size).x, cmax_width); + if (line_width > width) { + width = line_width; } } } else { - w = cmax_width; + width = cmax_width; } // Add space for completion icons. const int icon_hsep = get_theme_constant("hseparation", "ItemList"); - Size2 icon_area_size(row_height, row_height); - w += icon_area_size.width + icon_hsep; + const Size2 icon_area_size(row_height, row_height); + const int icon_area_width = icon_area_size.width + icon_hsep; + width += icon_area_width; - int line_from = CLAMP(completion_index - lines / 2, 0, completion_options_size - lines); + const int line_from = CLAMP(completion_index - row_count / 2, 0, completion_options_size - row_count); - for (int i = 0; i < lines; i++) { + for (int i = 0; i < row_count; 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; + width += icon_area_size.width; break; } } - int th = h + csb->get_minimum_size().y; + // Position completion panel + completion_rect.size.width = width + 2; + completion_rect.size.height = completion_rows_height; - if (cursor_pos.y + row_height + th > get_size().height) { - completion_rect.position.y = cursor_pos.y - th - (cache.line_spacing / 2.0f) - cursor_insert_offset_y; - } else { - completion_rect.position.y = cursor_pos.y + cache.font->get_height(cache.font_size) + (cache.line_spacing / 2.0f) + csb->get_offset().y - cursor_insert_offset_y; - completion_below = true; + if (completion_options_size <= maxlines) { + scroll_rectangle_width = 0; } - if (cursor_pos.x - nofs + w + scrollw > get_size().width) { - completion_rect.position.x = get_size().width - w - scrollw; + const Point2 csb_offset = csb->get_offset(); + + const int total_width = completion_rect.size.width + csb->get_minimum_size().x + scroll_rectangle_width; + const int total_height = completion_rect.size.height + csb->get_minimum_size().y; + + const int rect_left_border_x = cursor_pos.x - completion_base_width - icon_area_width - csb_offset.x; + const int rect_right_border_x = rect_left_border_x + total_width; + + if (rect_left_border_x < 0) { + // Anchor the completion panel to the left + completion_rect.position.x = 0; + } else if (rect_right_border_x > get_size().width) { + // Anchor the completion panel to the right + completion_rect.position.x = get_size().width - total_width; } else { - completion_rect.position.x = cursor_pos.x - nofs; + // Let the completion panel float with the cursor + completion_rect.position.x = rect_left_border_x; } - completion_rect.size.width = w + 2; - completion_rect.size.height = h; - if (completion_options_size <= maxlines) { - scrollw = 0; + if (cursor_pos.y + row_height + total_height > get_size().height && cursor_pos.y > total_height) { + // Completion panel above the cursor line + completion_rect.position.y = cursor_pos.y - total_height; + } else { + // Completion panel below the cursor line + completion_rect.position.y = cursor_pos.y + row_height; + completion_below = true; } - draw_style_box(csb, Rect2(completion_rect.position - csb->get_offset(), completion_rect.size + csb->get_minimum_size() + Size2(scrollw, 0))); + draw_style_box(csb, Rect2(completion_rect.position - csb_offset, completion_rect.size + csb->get_minimum_size() + Size2(scroll_rectangle_width, 0))); 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); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scroll_rectangle_width, 0)), cache.completion_background_color); } 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); + draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(completion_base_width, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color); - for (int i = 0; i < lines; i++) { + for (int i = 0; i < row_count; i++) { int l = line_from + i; ERR_CONTINUE(l < 0 || l >= completion_options_size); @@ -1548,14 +1612,17 @@ void TextEdit::_notification(int p_what) { } tl->set_align(HALIGN_LEFT); } + if (cache.outline_size > 0 && cache.outline_color.a > 0) { + tl->draw_outline(ci, title_pos, cache.outline_size, cache.outline_color); + } tl->draw(ci, title_pos, completion_options[l].font_color); } - if (scrollw) { + if (scroll_rectangle_width) { // Draw a small scroll rectangle to show a position in the options. float r = (float)maxlines / completion_options_size; float o = (float)line_from / completion_options_size; - draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scrollw, completion_rect.size.y * r), scrollc); + draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scroll_rectangle_width, completion_rect.size.y * r), scrollc); } completion_line_ofs = line_from; @@ -1563,7 +1630,7 @@ void TextEdit::_notification(int p_what) { // Check to see if the hint should be drawn. bool show_hint = false; - if (completion_hint != "") { + if (is_cursor_line_visible && completion_hint != "") { if (completion_active) { if (completion_below && !callhint_below) { show_hint = true; @@ -1635,7 +1702,7 @@ void TextEdit::_notification(int p_what) { } if (has_focus()) { - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); } @@ -1648,7 +1715,7 @@ void TextEdit::_notification(int p_what) { draw_caret = true; } - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + _get_cursor_pixel_pos(false), get_viewport()->get_window_id()); } @@ -1677,7 +1744,7 @@ void TextEdit::_notification(int p_what) { caret_blink_timer->stop(); } - if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { + if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); } @@ -1910,7 +1977,7 @@ void TextEdit::backspace_at_cursor() { cursor_set_column(prev_column); } -void TextEdit::indent_right() { +void TextEdit::indent_selected_lines_right() { int start_line; int end_line; @@ -1942,7 +2009,7 @@ void TextEdit::indent_right() { // 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); int spaces_to_add = _calculate_spaces_till_next_right_indent(left); - // Since we will add this much spaces we want move whole selection and cursor by this much. + // Since we will add these many spaces, we want to move the whole selection and cursor by this much. selection_offset = spaces_to_add; for (int j = 0; j < spaces_to_add; j++) { line_text = ' ' + line_text; @@ -1962,12 +2029,12 @@ void TextEdit::indent_right() { update(); } -void TextEdit::indent_left() { +void TextEdit::indent_selected_lines_left() { int start_line; int end_line; // Moving cursor and selection after unindenting can get tricky because - // changing content of line can move cursor and selection on it's own (if new line ends before previous position of either), + // changing content of line can move cursor and selection on its own (if new line ends before previous position of either), // therefore we just remember initial values and at the end of the operation offset them by number of removed characters. int removed_characters = 0; int initial_selection_end_column = selection.to_column; @@ -2033,9 +2100,626 @@ int TextEdit::_calculate_spaces_till_next_right_indent(int column) { return indent_size - column % indent_size; } +void TextEdit::_swap_current_input_direction() { + if (input_direction == TEXT_DIRECTION_LTR) { + input_direction = TEXT_DIRECTION_RTL; + } else { + input_direction = TEXT_DIRECTION_LTR; + } + cursor_set_column(cursor.column); + update(); +} + +void TextEdit::_new_line(bool p_split_current_line, bool p_above) { + if (readonly) { + return; + } + + String ins = "\n"; + + // Keep indentation. + int space_count = 0; + for (int i = 0; i < cursor.column; i++) { + if (text[cursor.line][i] == '\t') { + if (indent_using_spaces) { + ins += space_indent; + } else { + ins += "\t"; + } + space_count = 0; + } else if (text[cursor.line][i] == ' ') { + space_count++; + + if (space_count == indent_size) { + if (indent_using_spaces) { + ins += space_indent; + } else { + ins += "\t"; + } + space_count = 0; + } + } else { + break; + } + } + + if (is_folded(cursor.line)) { + unfold_line(cursor.line); + } + + bool brace_indent = false; + + // No need to indent if we are going upwards. + if (auto_indent && !p_above) { + // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment + // (i.e. colon/brace precedes current cursor position). + if (cursor.column > 0) { + bool indent_char_found = false; + bool should_indent = false; + char indent_char = ':'; + char c = text[cursor.line][cursor.column]; + + for (int i = 0; i < cursor.column; i++) { + c = text[cursor.line][i]; + switch (c) { + case ':': + case '{': + case '[': + case '(': + indent_char_found = true; + should_indent = true; + indent_char = c; + continue; + } + + if (indent_char_found && is_line_comment(cursor.line)) { + should_indent = true; + break; + } else if (indent_char_found && !_is_whitespace(c)) { + should_indent = false; + indent_char_found = false; + } + } + + if (!is_line_comment(cursor.line) && should_indent) { + if (indent_using_spaces) { + ins += space_indent; + } else { + ins += "\t"; + } + + // No need to move the brace below if we are not taking the text with us. + char32_t closing_char = _get_right_pair_symbol(indent_char); + if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column])) { + if (p_split_current_line) { + brace_indent = true; + ins += "\n" + ins.substr(1, ins.length() - 2); + } else { + brace_indent = false; + ins = "\n" + ins.substr(1, ins.length() - 2); + } + } + } + } + } + begin_complex_operation(); + bool first_line = false; + if (!p_split_current_line) { + if (p_above) { + if (cursor.line > 0) { + cursor_set_line(cursor.line - 1); + cursor_set_column(text[cursor.line].length()); + } else { + cursor_set_column(0); + first_line = true; + } + } else { + cursor_set_column(text[cursor.line].length()); + } + } + + insert_text_at_cursor(ins); + + if (first_line) { + cursor_set_line(0); + } else if (brace_indent) { + cursor_set_line(cursor.line - 1); + cursor_set_column(text[cursor.line].length()); + } + end_complex_operation(); +} + +void TextEdit::_indent_right() { + if (readonly) { + return; + } + + if (is_selection_active()) { + indent_selected_lines_right(); + } else { + // Simple indent. + if (indent_using_spaces) { + // Insert only as much spaces as needed till next indentation level. + int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); + String indent_to_insert = String(); + for (int i = 0; i < spaces_to_add; i++) { + indent_to_insert = ' ' + indent_to_insert; + } + _insert_text_at_cursor(indent_to_insert); + } else { + _insert_text_at_cursor("\t"); + } + } +} + +void TextEdit::_indent_left() { + if (readonly) { + return; + } + + if (is_selection_active()) { + indent_selected_lines_left(); + } else { + // Simple unindent. + int cc = cursor.column; + const String &line = text[cursor.line]; + + int left = _find_first_non_whitespace_column_of_line(line); + cc = MIN(cc, left); + + while (cc < indent_size && cc < left && line[cc] == ' ') { + cc++; + } + + if (cc > 0 && cc <= text[cursor.line].length()) { + if (text[cursor.line][cc - 1] == '\t') { + // Tabs unindentation. + _remove_text(cursor.line, cc - 1, cursor.line, cc); + if (cursor.column >= left) { + cursor_set_column(MAX(0, cursor.column - 1)); + } + update(); + } else { + // Spaces unindentation. + int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); + if (spaces_to_remove > 0) { + _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); + if (cursor.column > left - spaces_to_remove) { // Inside text? + cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); + } + update(); + } + } + } else if (cc == 0 && line.length() > 0 && line[0] == '\t') { + _remove_text(cursor.line, 0, cursor.line, 1); + update(); + } + } +} + +void TextEdit::_move_cursor_left(bool p_select, bool p_move_by_word) { + // Handle selection + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + if (p_move_by_word) { + int cc = cursor.column; + + if (cc == 0 && cursor.line > 0) { + cursor_set_line(cursor.line - 1); + cursor_set_column(text[cursor.line].length()); + } else { + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid()); + for (int i = words.size() - 1; i >= 0; i--) { + if (words[i].x < cc) { + cc = words[i].x; + break; + } + } + cursor_set_column(cc); + } + } else { + // If the cursor is at the start of the line, and not on the first line, move it up to the end of the previous line. + if (cursor.column == 0) { + if (cursor.line > 0) { + cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); + cursor_set_column(text[cursor.line].length()); + } + } else { + if (mid_grapheme_caret_enabled) { + cursor_set_column(cursor_get_column() - 1); + } else { + cursor_set_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column())); + } + } + } + + if (p_select) { + _post_shift_selection(); + } +} + +void TextEdit::_move_cursor_right(bool p_select, bool p_move_by_word) { + // Handle selection + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + if (p_move_by_word) { + int cc = cursor.column; + + if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) { + cursor_set_line(cursor.line + 1); + cursor_set_column(0); + } else { + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid()); + for (int i = 0; i < words.size(); i++) { + if (words[i].y > cc) { + cc = words[i].y; + break; + } + } + cursor_set_column(cc); + } + } else { + // If we are at the end of the line, move the caret to the next line down. + if (cursor.column == text[cursor.line].length()) { + if (cursor.line < text.size() - 1) { + cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); + cursor_set_column(0); + } + } else { + if (mid_grapheme_caret_enabled) { + cursor_set_column(cursor_get_column() + 1); + } else { + cursor_set_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column())); + } + } + } + + if (p_select) { + _post_shift_selection(); + } +} + +void TextEdit::_move_cursor_up(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + int cur_wrap_index = get_cursor_wrap_index(); + if (cur_wrap_index > 0) { + cursor_set_line(cursor.line, true, false, cur_wrap_index - 1); + } else if (cursor.line == 0) { + cursor_set_column(0); + } else { + int new_line = cursor.line - num_lines_from(cursor.line - 1, -1); + if (line_wraps(new_line)) { + cursor_set_line(new_line, true, false, times_line_wraps(new_line)); + } else { + cursor_set_line(new_line, true, false); + } + } + + if (p_select) { + _post_shift_selection(); + } + + _cancel_code_hint(); +} + +void TextEdit::_move_cursor_down(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + int cur_wrap_index = get_cursor_wrap_index(); + if (cur_wrap_index < times_line_wraps(cursor.line)) { + cursor_set_line(cursor.line, true, false, cur_wrap_index + 1); + } else if (cursor.line == get_last_unhidden_line()) { + cursor_set_column(text[cursor.line].length()); + } else { + int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1); + cursor_set_line(new_line, true, false, 0); + } + + if (p_select) { + _post_shift_selection(); + } + + _cancel_code_hint(); +} + +void TextEdit::_move_cursor_to_line_start(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + // Move cursor column to start of wrapped row and then to start of text. + Vector<String> rows = get_wrap_rows_text(cursor.line); + int wi = get_cursor_wrap_index(); + int row_start_col = 0; + for (int i = 0; i < wi; i++) { + row_start_col += rows[i].length(); + } + if (cursor.column == row_start_col || wi == 0) { + // Compute whitespace symbols sequence length. + int current_line_whitespace_len = 0; + while (current_line_whitespace_len < text[cursor.line].length()) { + char32_t c = text[cursor.line][current_line_whitespace_len]; + if (c != '\t' && c != ' ') { + break; + } + current_line_whitespace_len++; + } + + if (cursor_get_column() == current_line_whitespace_len) { + cursor_set_column(0); + } else { + cursor_set_column(current_line_whitespace_len); + } + } else { + cursor_set_column(row_start_col); + } + + if (p_select) { + _post_shift_selection(); + } + + _cancel_completion(); + completion_hint = ""; +} + +void TextEdit::_move_cursor_to_line_end(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + // Move cursor column to end of wrapped row and then to end of text. + Vector<String> rows = get_wrap_rows_text(cursor.line); + int wi = get_cursor_wrap_index(); + int row_end_col = -1; + for (int i = 0; i < wi + 1; i++) { + row_end_col += rows[i].length(); + } + if (wi == rows.size() - 1 || cursor.column == row_end_col) { + cursor_set_column(text[cursor.line].length()); + } else { + cursor_set_column(row_end_col); + } + + if (p_select) { + _post_shift_selection(); + } + _cancel_completion(); + completion_hint = ""; +} + +void TextEdit::_move_cursor_page_up(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + int wi; + int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1; + cursor_set_line(n_line, true, false, wi); + + if (p_select) { + _post_shift_selection(); + } + + _cancel_completion(); + completion_hint = ""; +} + +void TextEdit::_move_cursor_page_down(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + int wi; + int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1; + cursor_set_line(n_line, true, false, wi); + + if (p_select) { + _post_shift_selection(); + } + + _cancel_completion(); + completion_hint = ""; +} + +void TextEdit::_backspace(bool p_word, bool p_all_to_left) { + if (readonly) { + return; + } + + if (is_selection_active()) { + _delete_selection(); + return; + } + if (p_all_to_left) { + int cursor_current_column = cursor.column; + cursor.column = 0; + _remove_text(cursor.line, 0, cursor.line, cursor_current_column); + } else if (p_word) { + int line = cursor.line; + int column = cursor.column; + + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); + for (int i = words.size() - 1; i >= 0; i--) { + if (words[i].x < column) { + column = words[i].x; + break; + } + } + + _remove_text(line, column, cursor.line, cursor.column); + + cursor_set_line(line); + cursor_set_column(column); + } else { + // One character. + if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) { + unfold_line(cursor.line - 1); + } + backspace_at_cursor(); + } +} + +void TextEdit::_delete(bool p_word, bool p_all_to_right) { + if (readonly) { + return; + } + + if (is_selection_active()) { + _delete_selection(); + return; + } + int curline_len = text[cursor.line].length(); + + if (cursor.line == text.size() - 1 && cursor.column == curline_len) { + return; // Last line, last column: Nothing to do. + } + + int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1; + int next_column; + + if (p_all_to_right) { + // Delete everything to right of cursor + next_column = curline_len; + next_line = cursor.line; + } else if (p_word && cursor.column < curline_len - 1) { + // Delete next word to right of cursor + int line = cursor.line; + int column = cursor.column; + + Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); + for (int i = 0; i < words.size(); i++) { + if (words[i].y > column) { + column = words[i].y; + break; + } + } + + next_line = line; + next_column = column; + } else { + // Delete one character + next_column = cursor.column < curline_len ? (cursor.column + 1) : 0; + if (mid_grapheme_caret_enabled) { + next_column = cursor.column < curline_len ? (cursor.column + 1) : 0; + } else { + next_column = cursor.column < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), (cursor.column)) : 0; + } + } + + _remove_text(cursor.line, cursor.column, next_line, next_column); + update(); +} + +void TextEdit::_delete_selection() { + if (is_selection_active()) { + selection.active = false; + update(); + _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); + cursor_set_line(selection.from_line, true, false); + cursor_set_column(selection.from_column); + update(); + } +} + +void TextEdit::_move_cursor_document_start(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + cursor_set_line(0); + cursor_set_column(0); + + if (p_select) { + _post_shift_selection(); + } +} + +void TextEdit::_move_cursor_document_end(bool p_select) { + if (p_select) { + _pre_shift_selection(); + } else { + deselect(); + } + + cursor_set_line(get_last_unhidden_line(), true, false, 9999); + cursor_set_column(text[cursor.line].length()); + + if (p_select) { + _post_shift_selection(); + } +} + +void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete) { + if (p_update_auto_complete) { + _reset_caret_blink_timer(); + } + + if (p_had_selection) { + _delete_selection(); + } + + // Remove the old character if in insert mode and no selection. + if (insert_mode && !p_had_selection) { + begin_complex_operation(); + + // Make sure we don't try and remove empty space. + if (cursor.column < get_line(cursor.line).length()) { + _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); + } + } + + const char32_t chr[2] = { (char32_t)unicode, 0 }; + + // Clear completion hint when function closed + if (completion_hint != "" && unicode == ')') { + completion_hint = ""; + } + + if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } + + if ((insert_mode && !p_had_selection) || (selection.active != p_had_selection)) { + end_complex_operation(); + } + + if (p_update_auto_complete) { + _update_completion_candidates(); + } +} + void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const { float rows = p_mouse.y; - rows -= cache.style_normal->get_margin(MARGIN_TOP); + rows -= cache.style_normal->get_margin(SIDE_TOP); rows /= get_row_height(); rows += get_v_scroll_offset(); int first_vis_line = get_first_visible_line(); @@ -2061,8 +2745,20 @@ 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) + gutters_width + gutter_padding); + int colx = p_mouse.x - (cache.style_normal->get_margin(SIDE_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)) { + // Move back one if we are at the end of the row. + Vector<String> rows2 = get_wrap_rows_text(row); + int row_end_col = 0; + for (int i = 0; i < wrap_index + 1; i++) { + row_end_col += rows2[i].length(); + } + if (col >= row_end_col) { + col -= 1; + } + } RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index); if (is_layout_rtl()) { @@ -2089,7 +2785,7 @@ Vector2i TextEdit::_get_cursor_pixel_pos(bool p_adjust_viewport) { // Calculate final pixel position int y = (row - get_v_scroll_offset()) * get_row_height(); - int x = cache.style_normal->get_margin(MARGIN_LEFT) + gutters_width + gutter_padding - cursor.x_ofs; + int x = cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding - cursor.x_ofs; Rect2 l_caret, t_caret; TextServer::Direction l_dir, t_dir; @@ -2106,7 +2802,7 @@ Vector2i TextEdit::_get_cursor_pixel_pos(bool p_adjust_viewport) { void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const { float rows = p_mouse.y; - rows -= cache.style_normal->get_margin(MARGIN_TOP); + rows -= cache.style_normal->get_margin(SIDE_TOP); rows /= (minimap_char_size.y + minimap_line_spacing); rows += get_v_scroll_offset(); @@ -2177,14 +2873,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { return; } - if (mb->get_button_index() == BUTTON_WHEEL_UP) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP) { if (completion_index > 0) { completion_index--; completion_current = completion_options[completion_index]; update(); } } - if (mb->get_button_index() == BUTTON_WHEEL_DOWN) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN) { if (completion_index < completion_options.size() - 1) { completion_index++; completion_current = completion_options[completion_index]; @@ -2192,7 +2888,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { completion_index = CLAMP(completion_line_ofs + (mpos.y - completion_rect.position.y) / get_row_height(), 0, completion_options.size() - 1); completion_current = completion_options[completion_index]; @@ -2208,33 +2904,33 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (mb->is_pressed()) { - if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP && !mb->get_command()) { if (mb->get_shift()) { h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); } else if (v_scroll->is_visible()) { _scroll_up(3 * mb->get_factor()); } } - if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && !mb->get_command()) { if (mb->get_shift()) { h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor())); } else if (v_scroll->is_visible()) { _scroll_down(3 * mb->get_factor()); } } - if (mb->get_button_index() == BUTTON_WHEEL_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT) { h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor())); } - if (mb->get_button_index() == BUTTON_WHEEL_RIGHT) { + if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT) { h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor())); } - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { _reset_caret_blink_timer(); int row, col; _get_mouse_pos(Point2i(mpos.x, mpos.y), row, col); - int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + int left_margin = cache.style_normal->get_margin(SIDE_LEFT); for (int i = 0; i < gutters.size(); i++) { if (!gutters[i].draw || gutters[i].width <= 0) { continue; @@ -2268,7 +2964,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int prev_col = cursor.column; int prev_line = cursor.line; - cursor_set_line(row, true, false); + cursor_set_line(row, false, false); cursor_set_column(col); if (mb->get_shift() && (cursor.column != prev_col || cursor.line != prev_line)) { @@ -2293,8 +2989,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else { if (cursor.line < selection.selecting_line || (cursor.line == selection.selecting_line && cursor.column < selection.selecting_column)) { if (selection.shiftclick_left) { - SWAP(selection.from_column, selection.to_column); - SWAP(selection.from_line, selection.to_line); selection.shiftclick_left = !selection.shiftclick_left; } selection.from_column = cursor.column; @@ -2315,7 +3009,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } - } else { selection.active = false; selection.selecting_mode = SelectionMode::SELECTION_MODE_POINTER; @@ -2338,7 +3031,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { update(); } - if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { + if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) { _reset_caret_blink_timer(); int row, col; @@ -2364,12 +3057,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { menu->set_position(get_screen_transform().xform(mpos)); menu->set_size(Vector2(1, 1)); - // menu->set_scale(get_global_transform().get_scale()); + _generate_context_menu(); menu->popup(); grab_focus(); } } else { - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (mb->get_command() && highlighted_word != String()) { int row, col; _get_mouse_pos(Point2i(mpos.x, mpos.y), row, col); @@ -2425,7 +3118,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging. + if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { // Ignore if dragging. _reset_caret_blink_timer(); if (draw_minimap && !dragging_selection) { @@ -2458,13 +3151,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { Ref<InputEventKey> k = p_gui_input; if (k.is_valid()) { - k = k->duplicate(); // It will be modified later on. - + // Ctrl + Hover symbols #ifdef OSX_ENABLED if (k->get_keycode() == KEY_META) { #else if (k->get_keycode() == KEY_CONTROL) { - #endif if (select_identifiers_enabled) { if (k->is_pressed() && !dragging_minimap && !dragging_selection) { @@ -2474,1191 +3165,347 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { set_highlighted_word(String()); } } + return; } if (!k->is_pressed()) { return; } - if (completion_active) { - if (readonly) { - return; - } - - bool valid = true; - if (k->get_command() || k->get_metakey()) { - valid = false; - } - - if (valid) { - if (!k->get_alt()) { - if (k->get_keycode() == KEY_UP) { - if (completion_index > 0) { - completion_index--; - } else { - completion_index = completion_options.size() - 1; - } - completion_current = completion_options[completion_index]; - update(); - - accept_event(); - return; - } - - if (k->get_keycode() == KEY_DOWN) { - if (completion_index < completion_options.size() - 1) { - completion_index++; - } else { - completion_index = 0; - } - completion_current = completion_options[completion_index]; - update(); - - accept_event(); - return; - } - - if (k->get_keycode() == KEY_PAGEUP) { - completion_index -= get_theme_constant("completion_lines"); - if (completion_index < 0) { - completion_index = 0; - } - completion_current = completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_PAGEDOWN) { - completion_index += get_theme_constant("completion_lines"); - if (completion_index >= completion_options.size()) { - completion_index = completion_options.size() - 1; - } - completion_current = completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_HOME && completion_index > 0) { - completion_index = 0; - completion_current = completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_END && completion_index < completion_options.size() - 1) { - completion_index = completion_options.size() - 1; - completion_current = completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_KP_ENTER || k->get_keycode() == KEY_ENTER || k->get_keycode() == KEY_TAB) { - _confirm_completion(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_BACKSPACE) { - _reset_caret_blink_timer(); - - backspace_at_cursor(); - _update_completion_candidates(); - accept_event(); - return; - } - - if (k->get_keycode() == KEY_SHIFT) { - accept_event(); - return; - } - } - - if (k->get_unicode() > 32) { - _reset_caret_blink_timer(); - - 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 { - // Remove the old character if in insert mode. - if (insert_mode) { - begin_complex_operation(); - - // Make sure we don't try and remove empty space. - if (cursor.column < get_line(cursor.line).length()) { - _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); - } - } - - _insert_text_at_cursor(chr); - - if (insert_mode) { - end_complex_operation(); - } - } - _update_completion_candidates(); - accept_event(); - - return; - } - } - - _cancel_completion(); - } - - /* TEST CONTROL FIRST! */ - - // Some remaps for duplicate functions. - if (k->get_command() && !k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_keycode() == KEY_INSERT) { - k->set_keycode(KEY_C); - } - if (!k->get_command() && k->get_shift() && !k->get_alt() && !k->get_metakey() && k->get_keycode() == KEY_INSERT) { - k->set_keycode(KEY_V); - k->set_command(true); - k->set_shift(false); - } -#ifdef APPLE_STYLE_KEYS - if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { - uint32_t remap_key = KEY_UNKNOWN; - switch (k->get_keycode()) { - case KEY_F: { - remap_key = KEY_RIGHT; - } break; - case KEY_B: { - remap_key = KEY_LEFT; - } break; - case KEY_P: { - remap_key = KEY_UP; - } break; - case KEY_N: { - remap_key = KEY_DOWN; - } break; - case KEY_D: { - remap_key = KEY_DELETE; - } break; - case KEY_H: { - remap_key = KEY_BACKSPACE; - } break; - } - - if (remap_key != KEY_UNKNOWN) { - k->set_keycode(remap_key); - k->set_control(false); - } + // If a modifier has been pressed, and nothing else, return. + if (k->get_keycode() == KEY_CONTROL || k->get_keycode() == KEY_ALT || k->get_keycode() == KEY_SHIFT || k->get_keycode() == KEY_META) { + return; } -#endif _reset_caret_blink_timer(); + // Allow unicode handling if: + // * No Modifiers are pressed (except shift) + bool allow_unicode_handling = !(k->get_command() || k->get_control() || k->get_alt() || k->get_metakey()); + // Save here for insert mode, just in case it is cleared in the following section. bool had_selection = selection.active; - // Stuff to do when selection is active. - if (!readonly && selection.active) { - bool clear = false; - bool unselect = false; - bool dobreak = false; - - switch (k->get_keycode()) { - case KEY_TAB: { - if (k->get_shift()) { - indent_left(); - } else { - indent_right(); - } - dobreak = true; - accept_event(); - } break; - case KEY_X: - case KEY_C: - // Special keys often used with control, wait. - clear = (!k->get_command() || k->get_shift() || k->get_alt()); - break; - case KEY_DELETE: - if (!k->get_shift()) { - accept_event(); - clear = true; - dobreak = true; - } else if (k->get_command() || k->get_alt()) { - dobreak = true; - } - break; - case KEY_BACKSPACE: - accept_event(); - clear = true; - dobreak = true; - break; - case KEY_LEFT: - case KEY_RIGHT: - case KEY_UP: - case KEY_DOWN: - case KEY_PAGEUP: - case KEY_PAGEDOWN: - case KEY_HOME: - case KEY_END: - // Ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys). - if (k->get_command() || k->get_shift() || k->get_alt()) { - break; - } - unselect = true; - break; - - default: - if (k->get_unicode() >= 32 && !k->get_command() && !k->get_alt() && !k->get_metakey()) { - clear = true; - } - if (auto_brace_completion_enabled && _is_pair_left_symbol(k->get_unicode())) { - clear = false; - } - } - - if (unselect) { - selection.active = false; - selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; - update(); - } - if (clear) { - if (!dobreak) { - begin_complex_operation(); - } - selection.active = false; - update(); - _remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column); - cursor_set_line(selection.from_line, true, false); - cursor_set_column(selection.from_column); - update(); - } - if (dobreak) { - return; - } - } - selection.selecting_text = false; - bool keycode_handled = true; - - // Special keycode test. - - switch (k->get_keycode()) { - case KEY_KP_ENTER: - case KEY_ENTER: { - if (readonly) { - break; - } - - String ins = "\n"; - - // Keep indentation. - int space_count = 0; - for (int i = 0; i < cursor.column; i++) { - if (text[cursor.line][i] == '\t') { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - space_count = 0; - } else if (text[cursor.line][i] == ' ') { - space_count++; - - if (space_count == indent_size) { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - space_count = 0; - } - } else { - break; - } - } - - if (is_folded(cursor.line)) { - unfold_line(cursor.line); - } - - bool brace_indent = false; - - // No need to indent if we are going upwards. - if (auto_indent && !(k->get_command() && k->get_shift())) { - // Indent once again if previous line will end with ':','{','[','(' and the line is not a comment - // (i.e. colon/brace precedes current cursor position). - if (cursor.column > 0) { - bool indent_char_found = false; - bool should_indent = false; - char indent_char = ':'; - char c = text[cursor.line][cursor.column]; - - for (int i = 0; i < cursor.column; i++) { - c = text[cursor.line][i]; - switch (c) { - case ':': - case '{': - case '[': - case '(': - indent_char_found = true; - should_indent = true; - indent_char = c; - continue; - } - - if (indent_char_found && is_line_comment(cursor.line)) { - should_indent = true; - break; - } else if (indent_char_found && !_is_whitespace(c)) { - should_indent = false; - indent_char_found = false; - } - } - - if (!is_line_comment(cursor.line) && should_indent) { - if (indent_using_spaces) { - ins += space_indent; - } else { - ins += "\t"; - } - - // No need to move the brace below if we are not taking the text with us. - 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); - } - } - } - } - begin_complex_operation(); - bool first_line = false; - if (k->get_command()) { - if (k->get_shift()) { - if (cursor.line > 0) { - cursor_set_line(cursor.line - 1); - cursor_set_column(text[cursor.line].length()); - } else { - cursor_set_column(0); - first_line = true; - } - } else { - cursor_set_column(text[cursor.line].length()); - } - } - - insert_text_at_cursor(ins); - - if (first_line) { - cursor_set_line(0); - } else if (brace_indent) { - cursor_set_line(cursor.line - 1); - cursor_set_column(text[cursor.line].length()); - } - end_complex_operation(); - } break; - case KEY_ESCAPE: { - if (completion_hint != "") { - completion_hint = ""; - update(); - } else { - keycode_handled = false; - } - } break; - case KEY_TAB: { - if (k->get_command()) { - break; // Avoid tab when command. - } + // Check and handle all built in shortcuts. - if (readonly) { - break; - } + // AUTO-COMPLETE - if (is_selection_active()) { - if (k->get_shift()) { - indent_left(); - } else { - indent_right(); - } - } else { - if (k->get_shift()) { - // Simple unindent. - int cc = cursor.column; - const String &line = text[cursor.line]; - - int left = _find_first_non_whitespace_column_of_line(line); - cc = MIN(cc, left); - - while (cc < indent_size && cc < left && line[cc] == ' ') { - cc++; - } - - if (cc > 0 && cc <= text[cursor.line].length()) { - if (text[cursor.line][cc - 1] == '\t') { - // Tabs unindentation. - _remove_text(cursor.line, cc - 1, cursor.line, cc); - if (cursor.column >= left) { - cursor_set_column(MAX(0, cursor.column - 1)); - } - update(); - } else { - // Spaces unindentation. - int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc); - if (spaces_to_remove > 0) { - _remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc); - if (cursor.column > left - spaces_to_remove) { // Inside text? - cursor_set_column(MAX(0, cursor.column - spaces_to_remove)); - } - update(); - } - } - } else if (cc == 0 && line.length() > 0 && line[0] == '\t') { - _remove_text(cursor.line, 0, cursor.line, 1); - update(); - } - } else { - // Simple indent. - if (indent_using_spaces) { - // Insert only as much spaces as needed till next indentation level. - int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column); - String indent_to_insert = String(); - for (int i = 0; i < spaces_to_add; i++) { - indent_to_insert = ' ' + indent_to_insert; - } - _insert_text_at_cursor(indent_to_insert); - } else { - _insert_text_at_cursor("\t"); - } - } - } - - } break; - case KEY_BACKSPACE: { - if (readonly) { - break; - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_alt() && cursor.column > 1) { -#else - if (k->get_alt()) { - keycode_handled = false; - break; - } else if (k->get_command() && cursor.column > 1) { -#endif - int line = cursor.line; - int column = cursor.column; - - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); - for (int i = words.size() - 1; i >= 0; i--) { - if (words[i].x < column) { - column = words[i].x; - break; - } - } - - _remove_text(line, column, cursor.line, cursor.column); - - cursor_set_line(line); - cursor_set_column(column); - -#ifdef APPLE_STYLE_KEYS - } else if (k->get_command()) { - int cursor_current_column = cursor.column; - cursor.column = 0; - _remove_text(cursor.line, 0, cursor.line, cursor_current_column); -#endif - } else { - if (cursor.line > 0 && is_line_hidden(cursor.line - 1)) { - unfold_line(cursor.line - 1); - } - backspace_at_cursor(); - } - - } break; - case KEY_KP_4: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; - } - [[fallthrough]]; - } - case KEY_LEFT: { - if (k->get_shift()) { - _pre_shift_selection(); -#ifdef APPLE_STYLE_KEYS - } else { -#else - } else if (!k->get_alt()) { -#endif - deselect(); - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - // Start at first column (it's slightly faster that way) and look for the first non-whitespace character. - int new_cursor_pos = 0; - for (int i = 0; i < text[cursor.line].length(); ++i) { - if (!_is_whitespace(text[cursor.line][i])) { - new_cursor_pos = i; - break; - } - } - if (new_cursor_pos == cursor.column) { - // We're already at the first text character, so move to the very beginning of the line. - cursor_set_column(0); - } else { - // We're somewhere to the right of the first text character; move to the first one. - cursor_set_column(new_cursor_pos); - } - } else if (k->get_alt()) { -#else - if (k->get_alt()) { - keycode_handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor.column; - - if (cc == 0 && cursor.line > 0) { - cursor_set_line(cursor.line - 1); - cursor_set_column(text[cursor.line].length()); - } else { - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid()); - for (int i = words.size() - 1; i >= 0; i--) { - if (words[i].x < cc) { - cc = words[i].x; - break; - } - } - cursor_set_column(cc); - } + if (k->is_action("ui_text_completion_query", true)) { + query_code_comple(); + accept_event(); + return; + } - } else if (cursor.column == 0) { - if (cursor.line > 0) { - cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); - cursor_set_column(text[cursor.line].length()); - } + if (completion_active) { + if (k->is_action("ui_up", true)) { + if (completion_index > 0) { + completion_index--; } else { - if (mid_grapheme_caret_enabled) { - cursor_set_column(cursor_get_column() - 1); - } else { - cursor_set_column(TS->shaped_text_prev_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column())); - } - } - - if (k->get_shift()) { - _post_shift_selection(); - } - - } break; - case KEY_KP_6: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + completion_index = completion_options.size() - 1; } - [[fallthrough]]; + completion_current = completion_options[completion_index]; + update(); + accept_event(); + return; } - case KEY_RIGHT: { - if (k->get_shift()) { - _pre_shift_selection(); -#ifdef APPLE_STYLE_KEYS - } else { -#else - } else if (!k->get_alt()) { -#endif - deselect(); - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - cursor_set_column(text[cursor.line].length()); - } else if (k->get_alt()) { -#else - if (k->get_alt()) { - keycode_handled = false; - break; - } else if (k->get_command()) { -#endif - int cc = cursor.column; - - if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) { - cursor_set_line(cursor.line + 1); - cursor_set_column(0); - } else { - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(cursor.line)->get_rid()); - for (int i = 0; i < words.size(); i++) { - if (words[i].y > cc) { - cc = words[i].y; - break; - } - } - cursor_set_column(cc); - } - - } else if (cursor.column == text[cursor.line].length()) { - if (cursor.line < text.size() - 1) { - cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); - cursor_set_column(0); - } + if (k->is_action("ui_down", true)) { + if (completion_index < completion_options.size() - 1) { + completion_index++; } else { - if (mid_grapheme_caret_enabled) { - cursor_set_column(cursor_get_column() + 1); - } else { - cursor_set_column(TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), cursor_get_column())); - } - } - - if (k->get_shift()) { - _post_shift_selection(); - } - - } break; - case KEY_KP_8: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + completion_index = 0; } - [[fallthrough]]; + completion_current = completion_options[completion_index]; + update(); + accept_event(); + return; } - case KEY_UP: { - if (k->get_alt()) { - keycode_handled = false; - break; - } -#ifndef APPLE_STYLE_KEYS - if (k->get_command()) { -#else - if (k->get_command() && k->get_alt()) { -#endif - _scroll_lines_up(); - break; - } - - if (k->get_shift()) { - _pre_shift_selection(); - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - cursor_set_line(0); - } else -#endif - { - int cur_wrap_index = get_cursor_wrap_index(); - if (cur_wrap_index > 0) { - cursor_set_line(cursor.line, true, false, cur_wrap_index - 1); - } else if (cursor.line == 0) { - cursor_set_column(0); - } else { - int new_line = cursor.line - num_lines_from(cursor.line - 1, -1); - if (line_wraps(new_line)) { - cursor_set_line(new_line, true, false, times_line_wraps(new_line)); - } else { - cursor_set_line(new_line, true, false); - } - } - } - - if (k->get_shift()) { - _post_shift_selection(); - } - _cancel_code_hint(); - - } break; - case KEY_KP_2: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + if (k->is_action("ui_page_up", true)) { + completion_index -= get_theme_constant("completion_lines"); + if (completion_index < 0) { + completion_index = 0; } - [[fallthrough]]; + completion_current = completion_options[completion_index]; + update(); + accept_event(); + return; } - case KEY_DOWN: { - if (k->get_alt()) { - keycode_handled = false; - break; - } -#ifndef APPLE_STYLE_KEYS - if (k->get_command()) { -#else - if (k->get_command() && k->get_alt()) { -#endif - _scroll_lines_down(); - break; - } - - if (k->get_shift()) { - _pre_shift_selection(); - } - -#ifdef APPLE_STYLE_KEYS - if (k->get_command()) { - cursor_set_line(get_last_unhidden_line(), true, false, 9999); - } else -#endif - { - int cur_wrap_index = get_cursor_wrap_index(); - if (cur_wrap_index < times_line_wraps(cursor.line)) { - cursor_set_line(cursor.line, true, false, cur_wrap_index + 1); - } else if (cursor.line == get_last_unhidden_line()) { - cursor_set_column(text[cursor.line].length()); - } else { - int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1); - cursor_set_line(new_line, true, false, 0); - } - } - - if (k->get_shift()) { - _post_shift_selection(); - } - _cancel_code_hint(); - - } break; - case KEY_DELETE: { - if (readonly) { - break; - } - - if (k->get_shift() && !k->get_command() && !k->get_alt() && is_shortcut_keys_enabled()) { - cut(); - break; - } - - int curline_len = text[cursor.line].length(); - - if (cursor.line == text.size() - 1 && cursor.column == curline_len) { - break; // Nothing to do. - } - - int next_line = cursor.column < curline_len ? cursor.line : cursor.line + 1; - int next_column; - -#ifdef APPLE_STYLE_KEYS - if (k->get_alt() && cursor.column < curline_len - 1) { -#else - if (k->get_alt()) { - keycode_handled = false; - break; - } else if (k->get_command() && cursor.column < curline_len - 1) { -#endif - - int line = cursor.line; - int column = cursor.column; - - Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text.get_line_data(line)->get_rid()); - for (int i = 0; i < words.size(); i++) { - if (words[i].y > column) { - column = words[i].y; - break; - } - } - - next_line = line; - next_column = column; -#ifdef APPLE_STYLE_KEYS - } else if (k->get_command()) { - next_column = curline_len; - next_line = cursor.line; -#endif - } else { - if (mid_grapheme_caret_enabled) { - next_column = cursor.column < curline_len ? (cursor.column + 1) : 0; - } else { - next_column = cursor.column < curline_len ? TS->shaped_text_next_grapheme_pos(text.get_line_data(cursor.line)->get_rid(), (cursor.column)) : 0; - } + if (k->is_action("ui_page_down", true)) { + completion_index += get_theme_constant("completion_lines"); + if (completion_index >= completion_options.size()) { + completion_index = completion_options.size() - 1; } - - _remove_text(cursor.line, cursor.column, next_line, next_column); + completion_current = completion_options[completion_index]; update(); - - } break; - case KEY_KP_7: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; - } - [[fallthrough]]; + accept_event(); + return; } - case KEY_HOME: { -#ifdef APPLE_STYLE_KEYS - if (k->get_shift()) - _pre_shift_selection(); - - cursor_set_line(0); - - if (k->get_shift()) - _post_shift_selection(); - else if (k->get_command() || k->get_control()) - deselect(); -#else - if (k->get_shift()) { - _pre_shift_selection(); - } - - if (k->get_command()) { - cursor_set_line(0); - cursor_set_column(0); - } else { - // Move cursor column to start of wrapped row and then to start of text. - Vector<String> rows = get_wrap_rows_text(cursor.line); - int wi = get_cursor_wrap_index(); - int row_start_col = 0; - for (int i = 0; i < wi; i++) { - row_start_col += rows[i].length(); - } - if (cursor.column == row_start_col || wi == 0) { - // Compute whitespace symbols seq length. - int current_line_whitespace_len = 0; - while (current_line_whitespace_len < text[cursor.line].length()) { - char32_t c = text[cursor.line][current_line_whitespace_len]; - if (c != '\t' && c != ' ') { - break; - } - current_line_whitespace_len++; - } - - if (cursor_get_column() == current_line_whitespace_len) { - cursor_set_column(0); - } else { - cursor_set_column(current_line_whitespace_len); - } - } else { - cursor_set_column(row_start_col); - } - } - - if (k->get_shift()) { - _post_shift_selection(); - } else if (k->get_command() || k->get_control()) { - deselect(); - } - _cancel_completion(); - completion_hint = ""; -#endif - } break; - case KEY_KP_1: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + if (k->is_action("ui_home", true)) { + if (completion_index > 0) { + completion_index = 0; + completion_current = completion_options[completion_index]; + update(); } - [[fallthrough]]; + accept_event(); + return; } - case KEY_END: { -#ifdef APPLE_STYLE_KEYS - if (k->get_shift()) - _pre_shift_selection(); - - cursor_set_line(get_last_unhidden_line(), true, false, 9999); - - if (k->get_shift()) - _post_shift_selection(); - else if (k->get_command() || k->get_control()) - deselect(); -#else - if (k->get_shift()) { - _pre_shift_selection(); - } - - if (k->get_command()) { - cursor_set_line(get_last_unhidden_line(), true, false, 9999); - } - - // Move cursor column to end of wrapped row and then to end of text. - Vector<String> rows = get_wrap_rows_text(cursor.line); - int wi = get_cursor_wrap_index(); - int row_end_col = -1; - for (int i = 0; i < wi + 1; i++) { - row_end_col += rows[i].length(); - } - if (wi == rows.size() - 1 || cursor.column == row_end_col) { - cursor_set_column(text[cursor.line].length()); - } else { - cursor_set_column(row_end_col); - } - - if (k->get_shift()) { - _post_shift_selection(); - } else if (k->get_command() || k->get_control()) { - deselect(); - } - - _cancel_completion(); - completion_hint = ""; -#endif - } break; - case KEY_KP_9: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + if (k->is_action("ui_end", true)) { + if (completion_index < completion_options.size() - 1) { + completion_index = completion_options.size() - 1; + completion_current = completion_options[completion_index]; + update(); } - [[fallthrough]]; + accept_event(); + return; } - case KEY_PAGEUP: { - if (k->get_shift()) { - _pre_shift_selection(); - } - - int wi; - int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1; - cursor_set_line(n_line, true, false, wi); - - if (k->get_shift()) { - _post_shift_selection(); - } - + if (k->is_action("ui_accept", true) || k->is_action("ui_text_completion_accept", true)) { + _confirm_completion(); + accept_event(); + return; + } + if (k->is_action("ui_cancel", true)) { _cancel_completion(); - completion_hint = ""; + accept_event(); + return; + } - } break; - case KEY_KP_3: { - if (k->get_unicode() != 0) { - keycode_handled = false; - break; + // Handle Unicode here (if no modifiers active) and update autocomplete. + if (k->get_unicode() >= 32) { + if (allow_unicode_handling && !readonly) { + _handle_unicode_character(k->get_unicode(), had_selection, true); + accept_event(); + return; } - [[fallthrough]]; } - case KEY_PAGEDOWN: { - if (k->get_shift()) { - _pre_shift_selection(); - } - - int wi; - int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1; - cursor_set_line(n_line, true, false, wi); + } - if (k->get_shift()) { - _post_shift_selection(); - } + // NEWLINES. + if (k->is_action("ui_text_newline_above", true)) { + _new_line(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_newline_blank", true)) { + _new_line(false); + accept_event(); + return; + } + if (k->is_action("ui_text_newline", true)) { + _new_line(); + accept_event(); + return; + } - _cancel_completion(); - completion_hint = ""; + // INDENTATION. + if (k->is_action("ui_text_dedent", true)) { + _indent_left(); + accept_event(); + return; + } + if (k->is_action("ui_text_indent", true)) { + _indent_right(); + accept_event(); + return; + } - } break; - case KEY_A: { -#ifndef APPLE_STYLE_KEYS - if (!k->get_control() || k->get_shift() || k->get_alt()) { - keycode_handled = false; - break; - } - if (is_shortcut_keys_enabled()) { - select_all(); - } -#else - if ((!k->get_command() && !k->get_control())) { - keycode_handled = false; - break; - } - if (!k->get_shift() && k->get_command() && is_shortcut_keys_enabled()) - select_all(); - else if (k->get_control()) { - if (k->get_shift()) - _pre_shift_selection(); - - int current_line_whitespace_len = 0; - while (current_line_whitespace_len < text[cursor.line].length()) { - char32_t c = text[cursor.line][current_line_whitespace_len]; - if (c != '\t' && c != ' ') - break; - current_line_whitespace_len++; - } + // BACKSPACE AND DELETE. + if (k->is_action("ui_text_backspace_all_to_left", true)) { + _backspace(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_backspace_word", true)) { + _backspace(true); + accept_event(); + return; + } + if (k->is_action("ui_text_backspace", true)) { + _backspace(); + if (completion_active) { + _update_completion_candidates(); + } + accept_event(); + return; + } + if (k->is_action("ui_text_delete_all_to_right", true)) { + _delete(false, true); + accept_event(); + return; + } + if (k->is_action("ui_text_delete_word", true)) { + _delete(true); + accept_event(); + return; + } + if (k->is_action("ui_text_delete", true)) { + _delete(); + accept_event(); + return; + } - if (cursor_get_column() == current_line_whitespace_len) - cursor_set_column(0); - else - cursor_set_column(current_line_whitespace_len); + // SCROLLING. + if (k->is_action("ui_text_scroll_up", true)) { + _scroll_lines_up(); + accept_event(); + return; + } + if (k->is_action("ui_text_scroll_down", true)) { + _scroll_lines_down(); + accept_event(); + return; + } - if (k->get_shift()) - _post_shift_selection(); - else if (k->get_command() || k->get_control()) - deselect(); - } - } break; - case KEY_E: { - if (!k->get_control() || k->get_command() || k->get_alt()) { - keycode_handled = false; - break; - } + // SELECT ALL, CUT, COPY, PASTE. - if (k->get_shift()) - _pre_shift_selection(); + if (k->is_action("ui_text_select_all", true)) { + select_all(); + accept_event(); + return; + } + if (k->is_action("ui_cut", true)) { + cut(); + accept_event(); + return; + } + if (k->is_action("ui_copy", true)) { + copy(); + accept_event(); + return; + } + if (k->is_action("ui_paste", true)) { + paste(); + accept_event(); + return; + } - if (k->get_command()) - cursor_set_line(text.size() - 1, true, false); - cursor_set_column(text[cursor.line].length()); + // UNDO/REDO. + if (k->is_action("ui_undo", true)) { + undo(); + accept_event(); + return; + } + if (k->is_action("ui_redo", true)) { + redo(); + accept_event(); + return; + } - if (k->get_shift()) - _post_shift_selection(); - else if (k->get_command() || k->get_control()) - deselect(); + // MISC. - _cancel_completion(); + if (k->is_action("ui_menu", true)) { + if (context_menu_enabled) { + menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos())); + menu->set_size(Vector2(1, 1)); + _generate_context_menu(); + menu->popup(); + menu->grab_focus(); + } + accept_event(); + return; + } + if (k->is_action("ui_text_toggle_insert_mode", true)) { + set_insert_mode(!insert_mode); + accept_event(); + return; + } + if (k->is_action("ui_cancel", true)) { + if (completion_hint != "") { completion_hint = ""; -#endif - } break; - case (KEY_QUOTELEFT): { // Swap current input direction (primary cursor) - if (!k->get_command()) { - keycode_handled = false; - break; - } - - if (input_direction == TEXT_DIRECTION_LTR) { - input_direction = TEXT_DIRECTION_RTL; - } else { - input_direction = TEXT_DIRECTION_LTR; - } - cursor_set_column(cursor.column); update(); - } break; - case KEY_X: { - if (readonly) { - break; - } - if (!k->get_command() || k->get_shift() || k->get_alt()) { - keycode_handled = false; - break; - } - if (is_shortcut_keys_enabled()) { - cut(); - } - - } break; - case KEY_C: { - if (!k->get_command() || k->get_shift() || k->get_alt()) { - keycode_handled = false; - break; - } - - if (is_shortcut_keys_enabled()) { - copy(); - } - - } break; - case KEY_Z: { - if (readonly) { - break; - } - - if (!k->get_command()) { - keycode_handled = false; - break; - } - - if (is_shortcut_keys_enabled()) { - if (k->get_shift()) { - redo(); - } else { - undo(); - } - } - } break; - case KEY_Y: { - if (readonly) { - break; - } - - if (!k->get_command()) { - keycode_handled = false; - break; - } - - if (is_shortcut_keys_enabled()) { - redo(); - } - } break; - case KEY_V: { - if (readonly) { - break; - } - if (!k->get_command() || k->get_shift() || k->get_alt()) { - keycode_handled = false; - break; - } - - if (is_shortcut_keys_enabled()) { - paste(); - } - - } break; - case KEY_SPACE: { -#ifdef OSX_ENABLED - if (completion_enabled && k->get_metakey()) { // cmd-space is spotlight shortcut in OSX -#else - if (completion_enabled && k->get_command()) { -#endif - - query_code_comple(); - keycode_handled = true; - } else { - keycode_handled = false; - } + } + accept_event(); + return; + } + if (k->is_action("ui_swap_input_direction", true)) { + _swap_current_input_direction(); + accept_event(); + return; + } - } break; + // CURSOR MOVEMENT - case KEY_MENU: { - if (context_menu_enabled) { - menu->set_position(get_screen_transform().xform(_get_cursor_pixel_pos())); - menu->set_size(Vector2(1, 1)); - menu->popup(); - menu->grab_focus(); - } - } break; + k = k->duplicate(); + bool shift_pressed = k->get_shift(); + // Remove shift or else actions will not match. Use above variable for selection. + k->set_shift(false); - default: { - keycode_handled = false; - } break; + // CURSOR MOVEMENT - LEFT, RIGHT. + if (k->is_action("ui_text_caret_word_left", true)) { + _move_cursor_left(shift_pressed, true); + accept_event(); + return; } - - if (keycode_handled) { + if (k->is_action("ui_text_caret_left", true)) { + _move_cursor_left(shift_pressed, false); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_word_right", true)) { + _move_cursor_right(shift_pressed, true); accept_event(); + return; } - - if (k->get_keycode() == KEY_INSERT) { - set_insert_mode(!insert_mode); + if (k->is_action("ui_text_caret_right", true)) { + _move_cursor_right(shift_pressed, false); accept_event(); return; } - if (!keycode_handled && (!k->get_command() || (k->get_command() && k->get_alt()))) { // For German keyboards. - - if (k->get_unicode() >= 32) { - if (readonly) { - return; - } - - // Remove the old character if in insert mode and no selection. - if (insert_mode && !had_selection) { - begin_complex_operation(); - - // Make sure we don't try and remove empty space. - if (cursor.column < get_line(cursor.line).length()) { - _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); - } - } - - const char32_t chr[2] = { (char32_t)k->get_unicode(), 0 }; + // CURSOR MOVEMENT - UP, DOWN. + if (k->is_action("ui_text_caret_up", true)) { + _move_cursor_up(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_down", true)) { + _move_cursor_down(shift_pressed); + accept_event(); + return; + } - if (completion_hint != "" && k->get_unicode() == ')') { - completion_hint = ""; - } - if (auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { - _consume_pair_symbol(chr[0]); - } else { - _insert_text_at_cursor(chr); - } + // CURSOR MOVEMENT - DOCUMENT START/END. + if (k->is_action("ui_text_caret_document_start", true)) { // && shift_pressed) { + _move_cursor_document_start(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_document_end", true)) { // && shift_pressed) { + _move_cursor_document_end(shift_pressed); + accept_event(); + return; + } - if (insert_mode && !had_selection) { - end_complex_operation(); - } + // CURSOR MOVEMENT - LINE START/END. + if (k->is_action("ui_text_caret_line_start", true)) { + _move_cursor_to_line_start(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_line_end", true)) { + _move_cursor_to_line_end(shift_pressed); + accept_event(); + return; + } - if (selection.active != had_selection) { - end_complex_operation(); - } - accept_event(); - } + // CURSOR MOVEMENT - PAGE UP/DOWN. + if (k->is_action("ui_text_caret_page_up", true)) { + _move_cursor_page_up(shift_pressed); + accept_event(); + return; + } + if (k->is_action("ui_text_caret_page_down", true)) { + _move_cursor_page_down(shift_pressed); + accept_event(); + return; } - return; + if (allow_unicode_handling && !readonly && k->get_unicode() >= 32) { + // Handle Unicode (if no modifiers active). + _handle_unicode_character(k->get_unicode(), had_selection, false); + accept_event(); + return; + } } } @@ -3747,8 +3594,8 @@ void TextEdit::_scroll_lines_up() { if (!selection.active) { int cur_line = cursor.line; int cur_wrap = get_cursor_wrap_index(); - int last_vis_line = get_last_visible_line(); - int last_vis_wrap = get_last_visible_line_wrap_index(); + int last_vis_line = get_last_full_visible_line(); + int last_vis_wrap = get_last_full_visible_line_wrap_index(); if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) { cursor_set_line(last_vis_line, false, false, last_vis_wrap); @@ -4034,25 +3881,50 @@ int TextEdit::_get_control_height() const { return control_height; } +int TextEdit::_get_menu_action_accelerator(const String &p_action) { + const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action); + if (!events) { + return 0; + } + + // Use first event in the list for the accelerator. + const List<Ref<InputEvent>>::Element *first_event = events->front(); + if (!first_event) { + return 0; + } + + const Ref<InputEventKey> event = first_event->get(); + if (event.is_null()) { + return 0; + } + + // Use physical keycode if non-zero + if (event->get_physical_keycode() != 0) { + return event->get_physical_keycode_with_modifiers(); + } else { + return event->get_keycode_with_modifiers(); + } +} + void TextEdit::_generate_context_menu() { // Reorganize context menu. menu->clear(); if (!readonly) { - menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0); + menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0); } - menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0); + menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : 0); if (!readonly) { - menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0); + menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : 0); } menu->add_separator(); if (is_selecting_enabled()) { - menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0); + menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : 0); } if (!readonly) { menu->add_item(RTR("Clear"), MENU_CLEAR); menu->add_separator(); - menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0); - menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0); + menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_undo") : 0); + menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_redo") : 0); } menu->add_separator(); menu->add_submenu_item(RTR("Text writing direction"), "DirMenu"); @@ -4121,8 +3993,8 @@ void TextEdit::adjust_viewport_to_cursor() { int first_vis_line = get_first_visible_line(); int first_vis_wrap = cursor.wrap_ofs; - int last_vis_line = get_last_visible_line(); - int last_vis_wrap = get_last_visible_line_wrap_index(); + int last_vis_line = get_last_full_visible_line(); + int last_vis_wrap = get_last_full_visible_line_wrap_index(); if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) { // Cursor is above screen. @@ -4575,7 +4447,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { int row, col; _get_mouse_pos(p_pos, row, col); - int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + int left_margin = cache.style_normal->get_margin(SIDE_LEFT); int gutter = left_margin + gutters_width; if (p_pos.x < gutter) { for (int i = 0; i < gutters.size(); i++) { @@ -4593,7 +4465,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_ARROW; } - int xmargin_end = get_size().width - cache.style_normal->get_margin(MARGIN_RIGHT); + int xmargin_end = get_size().width - cache.style_normal->get_margin(SIDE_RIGHT); if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; } @@ -4891,11 +4763,13 @@ void TextEdit::_update_caches() { cache.completion_font_color = get_theme_color("completion_font_color"); cache.font = get_theme_font("font"); cache.font_size = get_theme_font_size("font_size"); + cache.outline_color = get_theme_color("font_outline_color"); + cache.outline_size = get_theme_constant("outline_size"); cache.caret_color = get_theme_color("caret_color"); cache.caret_background_color = get_theme_color("caret_background_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"); + cache.font_selected_color = get_theme_color("font_selected_color"); + cache.font_readonly_color = get_theme_color("font_readonly_color"); cache.selection_color = get_theme_color("selection_color"); cache.mark_color = get_theme_color("mark_color"); cache.current_line_color = get_theme_color("current_line_color"); @@ -5140,6 +5014,10 @@ void TextEdit::set_auto_indent(bool p_auto_indent) { } void TextEdit::cut() { + if (readonly) { + return; + } + if (!selection.active) { String clipboard = text[cursor.line]; DisplayServer::get_singleton()->clipboard_set(clipboard); @@ -5187,6 +5065,10 @@ void TextEdit::copy() { } void TextEdit::paste() { + if (readonly) { + return; + } + String clipboard = DisplayServer::get_singleton()->clipboard_get(); begin_complex_operation(); @@ -5197,7 +5079,7 @@ void TextEdit::paste() { cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - } else if (!cut_copy_line.empty() && cut_copy_line == clipboard) { + } else if (!cut_copy_line.is_empty() && cut_copy_line == clipboard) { cursor_set_column(0); String ins = "\n"; clipboard += ins; @@ -5890,6 +5772,10 @@ void TextEdit::_clear_redo() { } void TextEdit::undo() { + if (readonly) { + return; + } + _push_current_op(); if (undo_stack_pos == nullptr) { @@ -5940,6 +5826,9 @@ void TextEdit::undo() { } void TextEdit::redo() { + if (readonly) { + return; + } _push_current_op(); if (undo_stack_pos == nullptr) { @@ -6100,7 +5989,7 @@ double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const { } // Count the number of visible lines up to this line. - double new_line_scroll_pos = 0; + double new_line_scroll_pos = 0.0; int to = CLAMP(p_line, 0, text.size() - 1); for (int i = 0; i < to; i++) { if (!text.is_hidden(i)) { @@ -6135,19 +6024,19 @@ int TextEdit::get_first_visible_line() const { return CLAMP(cursor.line_ofs, 0, text.size() - 1); } -int TextEdit::get_last_visible_line() const { +int TextEdit::get_last_full_visible_line() const { int first_vis_line = get_first_visible_line(); int last_vis_line = 0; int wi; - last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1; + last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi) - 1; last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1); return last_vis_line; } -int TextEdit::get_last_visible_line_wrap_index() const { +int TextEdit::get_last_full_visible_line_wrap_index() const { int first_vis_line = get_first_visible_line(); int wi; - num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi); + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows(), wi); return wi; } @@ -6469,7 +6358,7 @@ void TextEdit::query_code_comple() { c--; } - bool ignored = completion_active && !completion_options.empty(); + bool ignored = completion_active && !completion_options.is_empty(); if (ignored) { ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_PLAIN_TEXT; const ScriptCodeCompletionOption *previous_option = nullptr; @@ -6878,7 +6767,7 @@ bool TextEdit::_set(const StringName &p_name, const Variant &p_value) { update(); } } - _change_notify(); + notify_property_list_changed(); return true; } @@ -7177,23 +7066,11 @@ void TextEdit::_bind_methods() { } TextEdit::TextEdit() { - setting_row = false; - draw_tabs = false; - draw_spaces = false; - override_selected_font_color = false; - draw_caret = true; - max_chars = 0; clear(); - wrap_enabled = false; - wrap_at = 0; - wrap_right_offset = 10; set_focus_mode(FOCUS_ALL); _update_caches(); - cache.line_spacing = 1; - cache.font_size = 16; set_default_cursor_shape(CURSOR_IBEAM); - indent_size = 4; text.set_indent_size(indent_size); text.clear(); @@ -7203,31 +7080,16 @@ TextEdit::TextEdit() { add_child(h_scroll); add_child(v_scroll); - updating_scrolls = false; - selection.active = false; - h_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved)); v_scroll->connect("value_changed", callable_mp(this, &TextEdit::_scroll_moved)); v_scroll->connect("scrolling", callable_mp(this, &TextEdit::_v_scroll_input)); - cursor_changed_dirty = false; - text_changed_dirty = false; - - selection.selecting_mode = SelectionMode::SELECTION_MODE_NONE; - selection.selecting_line = 0; - selection.selecting_column = 0; - selection.selecting_text = false; - selection.active = false; - - block_caret = false; - caret_blink_enabled = false; caret_blink_timer = memnew(Timer); add_child(caret_blink_timer); caret_blink_timer->set_wait_time(0.65); caret_blink_timer->connect("timeout", callable_mp(this, &TextEdit::_toggle_draw_caret)); cursor_set_blink_enabled(false); - right_click_moves_caret = true; idle_detect = memnew(Timer); add_child(idle_detect); @@ -7240,54 +7102,8 @@ TextEdit::TextEdit() { click_select_held->set_wait_time(0.05); click_select_held->connect("timeout", callable_mp(this, &TextEdit::_click_selection_held)); - current_op.type = TextOperation::TYPE_NONE; - undo_enabled = true; undo_stack_max_size = GLOBAL_GET("gui/common/text_edit_undo_stack_max_size"); - undo_stack_pos = nullptr; - setting_text = false; - last_dblclk = 0; - current_op.version = 0; - version = 0; - saved_version = 0; - completion_enabled = false; - completion_active = false; - completion_line_ofs = 0; - tooltip_obj = nullptr; - line_length_guidelines = false; - line_length_guideline_soft_col = 80; - line_length_guideline_hard_col = 100; - hiding_enabled = false; - next_operation_is_complex = false; - scroll_past_end_of_file_enabled = false; - auto_brace_completion_enabled = false; - brace_matching_enabled = false; - highlight_all_occurrences = false; - highlight_current_line = false; - indent_using_spaces = false; - space_indent = " "; - auto_indent = false; - insert_mode = false; - window_has_focus = true; - select_identifiers_enabled = false; - smooth_scroll_enabled = false; - scrolling = false; - minimap_clicked = false; - dragging_minimap = false; - can_drag_minimap = false; - minimap_scroll_ratio = 0; - minimap_scroll_click_pos = 0; - dragging_selection = false; - target_v_scroll = 0; - v_scroll_speed = 80; - draw_minimap = false; - minimap_width = 80; - minimap_char_size = Point2(1, 2); - minimap_line_spacing = 1; - - selecting_enabled = true; - context_menu_enabled = true; - shortcut_keys_enabled = true; menu = memnew(PopupMenu); add_child(menu); @@ -7322,12 +7138,10 @@ TextEdit::TextEdit() { menu_ctl->add_item(RTR("Soft hyphen (SHY)"), MENU_INSERT_SHY); menu->add_child(menu_ctl); - readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly. set_readonly(false); menu->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); menu_dir->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); menu_ctl->connect("id_pressed", callable_mp(this, &TextEdit::menu_option)); - first_draw = true; } TextEdit::~TextEdit() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 3f16ed1366..b0c7314c65 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -92,14 +92,11 @@ private: Vector<Vector2i> bidi_override; Ref<TextParagraph> data_buf; - bool marked; - bool hidden; + bool marked = false; + bool hidden = false; Line() { data_buf.instance(); - - marked = false; - hidden = false; } }; @@ -173,46 +170,31 @@ private: }; struct Cursor { - int last_fit_x; - int line, column; ///< cursor - int x_ofs, line_ofs, wrap_ofs; - Cursor() { - last_fit_x = 0; - line = 0; - column = 0; ///< cursor - x_ofs = 0; - line_ofs = 0; - wrap_ofs = 0; - } + int last_fit_x = 0; + int line = 0; + int column = 0; ///< cursor + int x_ofs = 0; + int line_ofs = 0; + int wrap_ofs = 0; } cursor; struct Selection { - SelectionMode selecting_mode; - int selecting_line, selecting_column; - int selected_word_beg, selected_word_end, selected_word_origin; - bool selecting_text; - - bool active; - - int from_line, from_column; - int to_line, to_column; - - bool shiftclick_left; - Selection() { - selecting_mode = SelectionMode::SELECTION_MODE_NONE; - selecting_line = 0; - selecting_column = 0; - selected_word_beg = 0; - selected_word_end = 0; - selected_word_origin = 0; - selecting_text = false; - active = false; - from_line = 0; - from_column = 0; - to_line = 0; - to_column = 0; - shiftclick_left = false; - } + SelectionMode selecting_mode = SelectionMode::SELECTION_MODE_NONE; + int selecting_line = 0; + int selecting_column = 0; + int selected_word_beg = 0; + int selected_word_end = 0; + int selected_word_origin = 0; + bool selecting_text = false; + + bool active = false; + + int from_line = 0; + int from_column = 0; + int to_line = 0; + int to_column = 0; + + bool shiftclick_left = false; } selection; Map<int, Dictionary> syntax_highlighting_cache; @@ -224,25 +206,16 @@ private: TYPE_REMOVE }; - Type type; - int from_line, from_column; - int to_line, to_column; + Type type = TYPE_NONE; + int from_line = 0; + int from_column = 0; + int to_line = 0; + int to_column = 0; String text; - uint32_t prev_version; - uint32_t version; - bool chain_forward; - bool chain_backward; - TextOperation() { - type = TYPE_NONE; - from_line = 0; - from_column = 0; - to_line = 0; - to_column = 0; - prev_version = 0; - version = 0; - chain_forward = false; - chain_backward = false; - } + uint32_t prev_version = 0; + uint32_t version = 0; + bool chain_forward = false; + bool chain_backward = false; }; String ime_text; @@ -251,7 +224,7 @@ private: TextOperation current_op; List<TextOperation> undo_stack; - List<TextOperation>::Element *undo_stack_pos; + List<TextOperation>::Element *undo_stack_pos = nullptr; int undo_stack_max_size; void _clear_redo(); @@ -264,20 +237,20 @@ private: Dictionary _get_line_syntax_highlighting(int p_line); Set<String> completion_prefixes; - bool completion_enabled; + bool completion_enabled = false; List<ScriptCodeCompletionOption> completion_sources; Vector<ScriptCodeCompletionOption> completion_options; - bool completion_active; - bool completion_forced; + bool completion_active = false; + bool completion_forced = false; ScriptCodeCompletionOption completion_current; String completion_base; - int completion_index; + int completion_index = 0; Rect2i completion_rect; - int completion_line_ofs; + int completion_line_ofs = 0; String completion_hint; - int completion_hint_offset; + int completion_hint_offset = 0; - bool setting_text; + bool setting_text = false; // data Text text; @@ -290,93 +263,93 @@ private: Array st_args; bool draw_control_chars = false; - uint32_t version; - uint32_t saved_version; + uint32_t version = 0; + uint32_t saved_version = 0; - int max_chars; - bool readonly; - bool indent_using_spaces; - int indent_size; - String space_indent; + int max_chars = 0; + bool readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly. + bool indent_using_spaces = false; + int indent_size = 4; + String space_indent = " "; Timer *caret_blink_timer; - bool caret_blink_enabled; - bool draw_caret; - bool window_has_focus; - bool block_caret; - bool right_click_moves_caret; + bool caret_blink_enabled = false; + bool draw_caret = true; + bool window_has_focus = true; + bool block_caret = false; + bool right_click_moves_caret = true; bool mid_grapheme_caret_enabled = false; - bool wrap_enabled; - int wrap_at; - int wrap_right_offset; - - bool first_draw; - bool setting_row; - bool draw_tabs; - bool draw_spaces; - bool override_selected_font_color; - bool cursor_changed_dirty; - bool text_changed_dirty; - bool undo_enabled; - bool line_length_guidelines; - int line_length_guideline_soft_col; - int line_length_guideline_hard_col; - bool hiding_enabled; - bool draw_minimap; - int minimap_width; - Point2 minimap_char_size; - int minimap_line_spacing; - - bool highlight_all_occurrences; - bool scroll_past_end_of_file_enabled; - bool auto_brace_completion_enabled; - bool brace_matching_enabled; - bool highlight_current_line; - bool auto_indent; + bool wrap_enabled = false; + int wrap_at = 0; + int wrap_right_offset = 10; + + bool first_draw = true; + bool setting_row = false; + bool draw_tabs = false; + bool draw_spaces = false; + bool override_selected_font_color = false; + bool cursor_changed_dirty = false; + bool text_changed_dirty = false; + bool undo_enabled = true; + bool line_length_guidelines = false; + int line_length_guideline_soft_col = 80; + int line_length_guideline_hard_col = 100; + bool hiding_enabled = false; + bool draw_minimap = false; + int minimap_width = 80; + Point2 minimap_char_size = Point2(1, 2); + int minimap_line_spacing = 1; + + bool highlight_all_occurrences = false; + bool scroll_past_end_of_file_enabled = false; + bool auto_brace_completion_enabled = false; + bool brace_matching_enabled = false; + bool highlight_current_line = false; + bool auto_indent = false; String cut_copy_line; - bool insert_mode; - bool select_identifiers_enabled; - - bool smooth_scroll_enabled; - bool scrolling; - bool dragging_selection; - bool dragging_minimap; - bool can_drag_minimap; - bool minimap_clicked; - double minimap_scroll_ratio; - double minimap_scroll_click_pos; - float target_v_scroll; - float v_scroll_speed; + bool insert_mode = false; + bool select_identifiers_enabled = false; + + bool smooth_scroll_enabled = false; + bool scrolling = false; + bool dragging_selection = false; + bool dragging_minimap = false; + bool can_drag_minimap = false; + bool minimap_clicked = false; + double minimap_scroll_ratio = 0.0; + double minimap_scroll_click_pos = 0.0; + float target_v_scroll = 0.0; + float v_scroll_speed = 80.0; String highlighted_word; - uint64_t last_dblclk; + uint64_t last_dblclk = 0; Timer *idle_detect; Timer *click_select_held; HScrollBar *h_scroll; VScrollBar *v_scroll; - bool updating_scrolls; + bool updating_scrolls = false; - Object *tooltip_obj; + Object *tooltip_obj = nullptr; StringName tooltip_func; Variant tooltip_ud; - bool next_operation_is_complex; + bool next_operation_is_complex = false; - bool callhint_below; + bool callhint_below = false; Vector2 callhint_offset; String search_text; - uint32_t search_flags; - int search_result_line; - int search_result_col; + uint32_t search_flags = 0; + int search_result_line = 0; + int search_result_col = 0; - bool selecting_enabled; + bool selecting_enabled = true; - bool context_menu_enabled; - bool shortcut_keys_enabled; + bool context_menu_enabled = true; + bool shortcut_keys_enabled = true; bool virtual_keyboard_enabled = true; void _generate_context_menu(); @@ -400,8 +373,8 @@ private: void set_line_as_center_visible(int p_line, int p_wrap_index = 0); void set_line_as_last_visible(int p_line, int p_wrap_index = 0); int get_first_visible_line() const; - int get_last_visible_line() const; - int get_last_visible_line_wrap_index() const; + int get_last_full_visible_line() const; + int get_last_full_visible_line_wrap_index() const; double get_visible_rows_offset() const; double get_v_scroll_offset() const; @@ -435,6 +408,7 @@ private: int _get_control_height() const; Point2 _get_local_mouse_pos() const; + int _get_menu_action_accelerator(const String &p_action); void _reset_caret_blink_timer(); void _toggle_draw_caret(); @@ -468,6 +442,26 @@ private: int _calculate_spaces_till_next_left_indent(int column); int _calculate_spaces_till_next_right_indent(int column); + // Methods used in shortcuts + void _swap_current_input_direction(); + void _new_line(bool p_split_current = true, bool p_above = false); + void _indent_right(); + void _indent_left(); + void _move_cursor_left(bool p_select, bool p_move_by_word = false); + void _move_cursor_right(bool p_select, bool p_move_by_word = false); + void _move_cursor_up(bool p_select); + void _move_cursor_down(bool p_select); + void _move_cursor_to_line_start(bool p_select); + void _move_cursor_to_line_end(bool p_select); + void _move_cursor_page_up(bool p_select); + void _move_cursor_page_down(bool p_select); + void _backspace(bool p_word = false, bool p_all_to_left = false); + void _delete(bool p_word = false, bool p_all_to_right = false); + void _delete_selection(); + void _move_cursor_document_start(bool p_select); + void _move_cursor_document_end(bool p_select); + void _handle_unicode_character(uint32_t unicode, bool p_had_selection, bool p_update_auto_complete); + protected: struct Cache { Ref<Texture2D> tab_icon; @@ -477,7 +471,9 @@ protected: Ref<StyleBox> style_focus; Ref<StyleBox> style_readonly; Ref<Font> font; - int font_size; + int font_size = 16; + int outline_size = 0; + Color outline_color; Color completion_background_color; Color completion_selected_color; Color completion_existing_color; @@ -485,8 +481,8 @@ protected: Color caret_color; Color caret_background_color; Color font_color; - Color font_color_selected; - Color font_color_readonly; + Color font_selected_color; + Color font_readonly_color; Color selection_color; Color mark_color; Color code_folding_color; @@ -498,12 +494,8 @@ protected: Color search_result_border_color; Color background_color; - int line_spacing; - int minimap_width; - Cache() { - line_spacing = 0; - minimap_width = 0; - } + int line_spacing = 1; + int minimap_width = 0; } cache; virtual String get_tooltip(const Point2 &p_pos) const override; @@ -668,8 +660,8 @@ public: int get_row_height() const; void backspace_at_cursor(); - void indent_left(); - void indent_right(); + void indent_selected_lines_left(); + void indent_selected_lines_right(); int get_indent_level(int p_line) const; bool is_line_comment(int p_line) const; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 4187d77083..f43e3d1a9d 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -29,7 +29,9 @@ /*************************************************************************/ #include "texture_button.h" + #include "core/typedefs.h" + #include <stdlib.h> Size2 TextureButton::get_minimum_size() const { @@ -247,8 +249,8 @@ void TextureButton::_bind_methods() { ClassDB::bind_method(D_METHOD("set_disabled_texture", "texture"), &TextureButton::set_disabled_texture); ClassDB::bind_method(D_METHOD("set_focused_texture", "texture"), &TextureButton::set_focused_texture); ClassDB::bind_method(D_METHOD("set_click_mask", "mask"), &TextureButton::set_click_mask); - ClassDB::bind_method(D_METHOD("set_expand", "p_expand"), &TextureButton::set_expand); - ClassDB::bind_method(D_METHOD("set_stretch_mode", "p_mode"), &TextureButton::set_stretch_mode); + ClassDB::bind_method(D_METHOD("set_expand", "expand"), &TextureButton::set_expand); + ClassDB::bind_method(D_METHOD("set_stretch_mode", "mode"), &TextureButton::set_stretch_mode); ClassDB::bind_method(D_METHOD("set_flip_h", "enable"), &TextureButton::set_flip_h); ClassDB::bind_method(D_METHOD("is_flipped_h"), &TextureButton::is_flipped_h); ClassDB::bind_method(D_METHOD("set_flip_v", "enable"), &TextureButton::set_flip_v); @@ -375,13 +377,4 @@ bool TextureButton::is_flipped_v() const { return vflip; } -TextureButton::TextureButton() { - expand = false; - stretch_mode = STRETCH_SCALE; - hflip = false; - vflip = false; - - _texture_region = Rect2(); - _position_rect = Rect2(); - _tile = false; -} +TextureButton::TextureButton() {} diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index 6f7ee65ae4..8361f3c341 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -54,15 +54,15 @@ private: Ref<Texture2D> disabled; Ref<Texture2D> focused; Ref<BitMap> click_mask; - bool expand; - StretchMode stretch_mode; + bool expand = false; + StretchMode stretch_mode = STRETCH_SCALE; Rect2 _texture_region; Rect2 _position_rect; - bool _tile; + bool _tile = false; - bool hflip; - bool vflip; + bool hflip = false; + bool vflip = false; protected: virtual Size2 get_minimum_size() const override; diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index b5115690ac..46ce9d5ca9 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -54,16 +54,16 @@ Ref<Texture2D> TextureProgressBar::get_over_texture() const { return over; } -void TextureProgressBar::set_stretch_margin(Margin p_margin, int p_size) { - ERR_FAIL_INDEX((int)p_margin, 4); - stretch_margin[p_margin] = p_size; +void TextureProgressBar::set_stretch_margin(Side p_side, int p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + stretch_margin[p_side] = p_size; update(); minimum_size_changed(); } -int TextureProgressBar::get_stretch_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return stretch_margin[p_margin]; +int TextureProgressBar::get_stretch_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return stretch_margin[p_side]; } void TextureProgressBar::set_nine_patch_stretch(bool p_stretch) { @@ -78,7 +78,7 @@ bool TextureProgressBar::get_nine_patch_stretch() const { Size2 TextureProgressBar::get_minimum_size() const { if (nine_patch_stretch) { - return Size2(stretch_margin[MARGIN_LEFT] + stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_TOP] + stretch_margin[MARGIN_BOTTOM]); + return Size2(stretch_margin[SIDE_LEFT] + stretch_margin[SIDE_RIGHT], stretch_margin[SIDE_TOP] + stretch_margin[SIDE_BOTTOM]); } else if (under.is_valid()) { return under->get_size(); } else if (over.is_valid()) { @@ -145,9 +145,9 @@ Point2 TextureProgressBar::unit_val_to_uv(float val) { float angle = (val * Math_TAU) - Math_PI * 0.5; Point2 dir = Vector2(Math::cos(angle), Math::sin(angle)); float t1 = 1.0; - float cp = 0; - float cq = 0; - float cr = 0; + float cp = 0.0; + float cq = 0.0; + float cr = 0.0; float edgeLeft = 0.0; float edgeRight = 1.0; float edgeBottom = 0.0; @@ -206,8 +206,8 @@ Point2 TextureProgressBar::get_relative_center() { void TextureProgressBar::draw_nine_patch_stretched(const Ref<Texture2D> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) { Vector2 texture_size = p_texture->get_size(); - Vector2 topleft = Vector2(stretch_margin[MARGIN_LEFT], stretch_margin[MARGIN_TOP]); - Vector2 bottomright = Vector2(stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_BOTTOM]); + Vector2 topleft = Vector2(stretch_margin[SIDE_LEFT], stretch_margin[SIDE_TOP]); + Vector2 bottomright = Vector2(stretch_margin[SIDE_RIGHT], stretch_margin[SIDE_BOTTOM]); Rect2 src_rect = Rect2(Point2(), texture_size); Rect2 dst_rect = Rect2(Point2(), get_size()); @@ -523,10 +523,10 @@ void TextureProgressBar::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "radial_center_offset"), "set_radial_center_offset", "get_radial_center_offset"); ADD_GROUP("Stretch", "stretch_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "nine_patch_stretch"), "set_nine_patch_stretch", "get_nine_patch_stretch"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_left", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_top", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_right", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "stretch_margin_bottom", PROPERTY_HINT_RANGE, "0,16384,1"), "set_stretch_margin", "get_stretch_margin", SIDE_BOTTOM); BIND_ENUM_CONSTANT(FILL_LEFT_TO_RIGHT); BIND_ENUM_CONSTANT(FILL_RIGHT_TO_LEFT); @@ -540,17 +540,5 @@ void TextureProgressBar::_bind_methods() { } TextureProgressBar::TextureProgressBar() { - mode = FILL_LEFT_TO_RIGHT; - rad_init_angle = 0; - rad_center_off = Point2(); - rad_max_degrees = 360; set_mouse_filter(MOUSE_FILTER_PASS); - - nine_patch_stretch = false; - stretch_margin[MARGIN_LEFT] = 0; - stretch_margin[MARGIN_RIGHT] = 0; - stretch_margin[MARGIN_BOTTOM] = 0; - stretch_margin[MARGIN_TOP] = 0; - - tint_under = tint_progress = tint_over = Color(1, 1, 1); } diff --git a/scene/gui/texture_progress_bar.h b/scene/gui/texture_progress_bar.h index 342e719a59..a3883a7017 100644 --- a/scene/gui/texture_progress_bar.h +++ b/scene/gui/texture_progress_bar.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -78,8 +78,8 @@ public: void set_over_texture(const Ref<Texture2D> &p_texture); Ref<Texture2D> get_over_texture() const; - void set_stretch_margin(Margin p_margin, int p_size); - int get_stretch_margin(Margin p_margin) const; + void set_stretch_margin(Side p_side, int p_size); + int get_stretch_margin(Side p_side) const; void set_nine_patch_stretch(bool p_stretch); bool get_nine_patch_stretch() const; @@ -98,13 +98,15 @@ public: TextureProgressBar(); private: - FillMode mode; - float rad_init_angle; - float rad_max_degrees; + FillMode mode = FILL_LEFT_TO_RIGHT; + float rad_init_angle = 0.0; + float rad_max_degrees = 360.0; Point2 rad_center_off; - bool nine_patch_stretch; - int stretch_margin[4]; - Color tint_under, tint_progress, tint_over; + bool nine_patch_stretch = false; + int stretch_margin[4] = {}; + Color tint_under = Color(1, 1, 1); + Color tint_progress = Color(1, 1, 1); + Color tint_over = Color(1, 1, 1); Point2 unit_val_to_uv(float val); Point2 get_relative_center(); diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp index 58e7249284..1cba88e06f 100644 --- a/scene/gui/texture_rect.cpp +++ b/scene/gui/texture_rect.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -217,11 +217,7 @@ bool TextureRect::is_flipped_v() const { } TextureRect::TextureRect() { - expand = false; - hflip = false; - vflip = false; set_mouse_filter(MOUSE_FILTER_PASS); - stretch_mode = STRETCH_SCALE_ON_EXPAND; } TextureRect::~TextureRect() { diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h index e39545f679..0f93d5732f 100644 --- a/scene/gui/texture_rect.h +++ b/scene/gui/texture_rect.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -49,11 +49,11 @@ public: }; private: - bool expand; - bool hflip; - bool vflip; + bool expand = false; + bool hflip = false; + bool vflip = false; Ref<Texture2D> texture; - StretchMode stretch_mode; + StretchMode stretch_mode = STRETCH_SCALE_ON_EXPAND; void _texture_changed(); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 063a5e7ac1..abfea241f3 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -163,7 +163,7 @@ void TreeItem::set_text(int p_column, String p_text) { cells.write[p_column].max = INT_MIN; for (int i = 0; i < strings.size(); i++) { int value = i; - if (!strings[i].get_slicec(':', 1).empty()) { + if (!strings[i].get_slicec(':', 1).is_empty()) { value = strings[i].get_slicec(':', 1).to_int(); } cells.write[p_column].min = MIN(cells[p_column].min, value); @@ -320,7 +320,7 @@ int TreeItem::get_icon_max_width(int p_column) const { void TreeItem::set_range(int p_column, double p_value) { ERR_FAIL_INDEX(p_column, cells.size()); if (cells[p_column].step > 0) { - p_value = Math::stepify(p_value, cells[p_column].step); + p_value = Math::snapped(p_value, cells[p_column].step); } if (p_value < cells[p_column].min) { p_value = cells[p_column].min; @@ -410,6 +410,14 @@ bool TreeItem::is_collapsed() { return collapsed; } +void TreeItem::uncollapse_tree() { + TreeItem *t = this; + while (t) { + t->set_collapsed(false); + t = t->parent; + } +} + void TreeItem::set_custom_minimum_height(int p_height) { custom_min_height = p_height; _changed_notify(); @@ -842,6 +850,8 @@ void TreeItem::_bind_methods() { ClassDB::bind_method(D_METHOD("set_collapsed", "enable"), &TreeItem::set_collapsed); ClassDB::bind_method(D_METHOD("is_collapsed"), &TreeItem::is_collapsed); + ClassDB::bind_method(D_METHOD("uncollapse_tree"), &TreeItem::uncollapse_tree); + ClassDB::bind_method(D_METHOD("set_custom_minimum_height", "height"), &TreeItem::set_custom_minimum_height); ClassDB::bind_method(D_METHOD("get_custom_minimum_height"), &TreeItem::get_custom_minimum_height); @@ -1018,7 +1028,7 @@ void Tree::update_cache() { cache.custom_button_font_highlight = get_theme_color("custom_button_font_highlight"); cache.font_color = get_theme_color("font_color"); - cache.font_color_selected = get_theme_color("font_color_selected"); + cache.font_selected_color = get_theme_color("font_selected_color"); cache.guide_color = get_theme_color("guide_color"); cache.drop_position_color = get_theme_color("drop_position_color"); cache.hseparation = get_theme_constant("hseparation"); @@ -1118,7 +1128,7 @@ int Tree::get_item_height(TreeItem *p_item) const { return height; } -void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color) { +void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color) { ERR_FAIL_COND(cache.font.is_null()); Rect2i rect = p_rect; @@ -1160,6 +1170,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co Point2 draw_pos = rect.position; draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0); p_cell.text_buf->set_width(MAX(0, rect.size.width)); + if (p_ol_size > 0 && p_ol_color.a > 0) { + p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color); + } p_cell.text_buf->draw(ci, draw_pos, p_color); rect.position.x += ts.width + cache.hseparation; rect.size.x -= ts.width + cache.hseparation; @@ -1182,6 +1195,9 @@ void Tree::draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Co Point2 draw_pos = rect.position; draw_pos.y += Math::floor((rect.size.y - p_cell.text_buf->get_size().y) / 2.0); p_cell.text_buf->set_width(MAX(0, rect.size.width)); + if (p_ol_size > 0 && p_ol_color.a > 0) { + p_cell.text_buf->draw_outline(ci, draw_pos, p_ol_size, p_ol_color); + } p_cell.text_buf->draw(ci, draw_pos, p_color); } } @@ -1212,7 +1228,7 @@ void Tree::update_item_cell(TreeItem *p_item, int p_col) { Vector<String> strings = p_item->cells[p_col].text.split(","); for (int j = 0; j < strings.size(); j++) { int value = j; - if (!strings[j].get_slicec(':', 1).empty()) { + if (!strings[j].get_slicec(':', 1).is_empty()) { value = strings[j].get_slicec(':', 1).to_int(); } if (option == value) { @@ -1358,9 +1374,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (i == 0) { if (p_item->cells[0].selected && select_mode == SELECT_ROW) { - Rect2i row_rect = Rect2i(Point2i(cache.bg->get_margin(MARGIN_LEFT), item_rect.position.y), Size2i(get_size().width - cache.bg->get_minimum_size().width, item_rect.size.y)); + Rect2i row_rect = Rect2i(Point2i(cache.bg->get_margin(SIDE_LEFT), item_rect.position.y), Size2i(get_size().width - cache.bg->get_minimum_size().width, item_rect.size.y)); //Rect2 r = Rect2i(row_rect.pos,row_rect.size); - //r.grow(cache.selected->get_margin(MARGIN_LEFT)); + //r.grow(cache.selected->get_margin(SIDE_LEFT)); if (rtl) { row_rect.position.x = get_size().width - row_rect.position.x - row_rect.size.x; } @@ -1433,7 +1449,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } } - Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_color_selected" : "font_color"); + Color col = p_item->cells[i].custom_color ? p_item->cells[i].color : get_theme_color(p_item->cells[i].selected ? "font_selected_color" : "font_color"); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); Color icon_col = p_item->cells[i].icon_color; if (p_item->cells[i].dirty) { @@ -1450,7 +1468,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 switch (p_item->cells[i].mode) { case TreeItem::CELL_MODE_STRING: { - draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col); + draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color); } break; case TreeItem::CELL_MODE_CHECK: { Ref<Texture2D> checked = cache.checked; @@ -1471,7 +1489,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 item_rect.size.x -= check_w; item_rect.position.x += check_w; - draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col); + draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color); } break; case TreeItem::CELL_MODE_RANGE: { @@ -1485,8 +1503,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 p_item->cells.write[i].text_buf->set_width(cell_width); if (rtl) { + if (outline_size > 0 && font_outline_color.a > 0) { + p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color); + } p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col); } else { + if (outline_size > 0 && font_outline_color.a > 0) { + p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } p_item->cells[i].text_buf->draw(ci, text_pos, col); } @@ -1501,8 +1525,14 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 int cell_width = item_rect.size.x - updown->get_width(); if (rtl) { + if (outline_size > 0 && font_outline_color.a > 0) { + p_item->cells[i].text_buf->draw_outline(ci, text_pos + Vector2(cell_width - text_width, 0), outline_size, font_outline_color); + } p_item->cells[i].text_buf->draw(ci, text_pos + Vector2(cell_width - text_width, 0), col); } else { + if (outline_size > 0 && font_outline_color.a > 0) { + p_item->cells[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } p_item->cells[i].text_buf->draw(ci, text_pos, col); } @@ -1543,7 +1573,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 } if (!p_item->cells[i].editable) { - draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col); + draw_item_rect(p_item->cells.write[i], item_rect, col, icon_col, outline_size, font_outline_color); break; } @@ -1558,7 +1588,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (p_item->cells[i].custom_button) { if (cache.hover_item == p_item && cache.hover_cell == i) { - if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) { draw_style_box(cache.custom_button_pressed, ir); } else { draw_style_box(cache.custom_button_hover, ir); @@ -1571,7 +1601,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 ir.position += cache.custom_button->get_offset(); } - draw_item_rect(p_item->cells.write[i], ir, col, icon_col); + draw_item_rect(p_item->cells.write[i], ir, col, icon_col, outline_size, font_outline_color); downarrow->draw(ci, arrow_pos); @@ -1795,7 +1825,7 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) { } void Tree::_range_click_timeout() { - if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) { + if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(MOUSE_BUTTON_LEFT)) { Point2 pos = get_local_mouse_position() - cache.bg->get_offset(); if (show_column_titles) { pos.y -= _get_title_button_height(); @@ -1813,7 +1843,7 @@ void Tree::_range_click_timeout() { propagate_mouse_activated = false; // done from outside, so signal handler can't clear the tree in the middle of emit (which is a common case) blocked++; - propagate_mouse_event(pos + cache.offset, 0, 0, false, root, BUTTON_LEFT, mb); + propagate_mouse_event(pos + cache.offset, 0, 0, false, root, MOUSE_BUTTON_LEFT, mb); blocked--; if (range_click_timer->is_one_shot()) { @@ -1887,7 +1917,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool return -1; } else if (col == 0) { int margin = x_ofs + cache.item_margin; //-cache.hseparation; - //int lm = cache.bg->get_margin(MARGIN_LEFT); + //int lm = cache.bg->get_margin(SIDE_LEFT); col_width -= margin; col_ofs += margin; x -= margin; @@ -1930,7 +1960,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool col_width -= w + cache.button_margin; } - if (p_button == BUTTON_LEFT || (p_button == BUTTON_RIGHT && allow_rmb_select)) { + if (p_button == MOUSE_BUTTON_LEFT || (p_button == MOUSE_BUTTON_RIGHT && allow_rmb_select)) { /* process selection */ if (p_doubleclick && (!c.editable || c.mode == TreeItem::CELL_MODE_CUSTOM || c.mode == TreeItem::CELL_MODE_ICON /*|| c.mode==TreeItem::CELL_MODE_CHECK*/)) { //it's confusing for check @@ -1942,10 +1972,10 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool } if (select_mode == SELECT_MULTI && p_mod->get_command() && c.selectable) { - if (!c.selected || p_button == BUTTON_RIGHT) { + if (!c.selected || p_button == MOUSE_BUTTON_RIGHT) { p_item->select(col); emit_signal("multi_selected", p_item, col, true); - if (p_button == BUTTON_RIGHT) { + if (p_button == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", get_local_mouse_position()); } @@ -1962,21 +1992,21 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool bool inrange = false; select_single_item(p_item, root, col, selected_item, &inrange); - if (p_button == BUTTON_RIGHT) { + if (p_button == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", get_local_mouse_position()); } } else { int icount = _count_selected_items(root); - if (select_mode == SELECT_MULTI && icount > 1 && p_button != BUTTON_RIGHT) { + if (select_mode == SELECT_MULTI && icount > 1 && p_button != MOUSE_BUTTON_RIGHT) { single_select_defer = p_item; single_select_defer_column = col; } else { - if (p_button != BUTTON_RIGHT || !c.selected) { + if (p_button != MOUSE_BUTTON_RIGHT || !c.selected) { select_single_item(p_item, root, col); } - if (p_button == BUTTON_RIGHT) { + if (p_button == MOUSE_BUTTON_RIGHT) { emit_signal("item_rmb_selected", get_local_mouse_position()); } } @@ -2031,7 +2061,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool popup_menu->clear(); for (int i = 0; i < c.text.get_slice_count(","); i++) { String s = c.text.get_slicec(',', i); - popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).empty() ? i : s.get_slicec(':', 1).to_int()); + popup_menu->add_item(s.get_slicec(':', 0), s.get_slicec(':', 1).is_empty() ? i : s.get_slicec(':', 1).to_int()); } popup_menu->set_size(Size2(col_width, 0)); @@ -2046,7 +2076,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool /* touching the combo */ bool up = p_pos.y < (item_h / 2); - if (p_button == BUTTON_LEFT) { + if (p_button == MOUSE_BUTTON_LEFT) { if (range_click_timer->get_time_left() == 0) { range_item_last = p_item; range_up_last = up; @@ -2063,13 +2093,13 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool item_edited(col, p_item); - } else if (p_button == BUTTON_RIGHT) { + } else if (p_button == MOUSE_BUTTON_RIGHT) { p_item->set_range(col, (up ? c.max : c.min)); item_edited(col, p_item); - } else if (p_button == BUTTON_WHEEL_UP) { + } else if (p_button == MOUSE_BUTTON_WHEEL_UP) { p_item->set_range(col, c.val + c.step); item_edited(col, p_item); - } else if (p_button == BUTTON_WHEEL_DOWN) { + } else if (p_button == MOUSE_BUTTON_WHEEL_DOWN) { p_item->set_range(col, c.val - c.step); item_edited(col, p_item); } @@ -2102,14 +2132,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool } if (!p_item->cells[col].custom_button || !on_arrow) { - item_edited(col, p_item, p_button == BUTTON_LEFT); + item_edited(col, p_item, p_button == MOUSE_BUTTON_LEFT); } click_handled = true; return -1; } break; }; - if (!bring_up_editor || p_button != BUTTON_LEFT) { + if (!bring_up_editor || p_button != MOUSE_BUTTON_LEFT) { return -1; } @@ -2149,7 +2179,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool item_h += child_h; } } - if (p_item == root && p_button == BUTTON_RIGHT) { + if (p_item == root && p_button == MOUSE_BUTTON_RIGHT) { emit_signal("empty_rmb", get_local_mouse_position()); } } @@ -2191,7 +2221,7 @@ void Tree::_text_editor_enter(String p_text) { case TreeItem::CELL_MODE_RANGE: { c.val = p_text.to_float(); if (c.step > 0) { - c.val = Math::stepify(c.val, c.step); + c.val = Math::snapped(c.val, c.step); } if (c.val < c.min) { c.val = c.min; @@ -2690,7 +2720,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { bool rtl = is_layout_rtl(); if (!b->is_pressed()) { - if (b->get_button_index() == BUTTON_LEFT) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT) { Point2 pos = b->get_position(); if (rtl) { pos.x = get_size().width - pos.x; @@ -2771,8 +2801,8 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } switch (b->get_button_index()) { - case BUTTON_RIGHT: - case BUTTON_LEFT: { + case MOUSE_BUTTON_RIGHT: + case MOUSE_BUTTON_LEFT: { Ref<StyleBox> bg = cache.bg; Point2 pos = b->get_position(); @@ -2785,7 +2815,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { pos.y -= _get_title_button_height(); if (pos.y < 0) { - if (b->get_button_index() == BUTTON_LEFT) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT) { pos.x += cache.offset.x; int len = 0; for (int i = 0; i < columns.size(); i++) { @@ -2803,7 +2833,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } if (!root || (!root->get_children() && hide_root)) { - if (b->get_button_index() == BUTTON_RIGHT && allow_rmb_select) { + if (b->get_button_index() == MOUSE_BUTTON_RIGHT && allow_rmb_select) { emit_signal("empty_tree_rmb_selected", get_local_mouse_position()); } break; @@ -2824,7 +2854,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } - if (b->get_button_index() == BUTTON_RIGHT) { + if (b->get_button_index() == MOUSE_BUTTON_RIGHT) { break; } @@ -2847,7 +2877,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { set_physics_process_internal(true); } - if (b->get_button_index() == BUTTON_LEFT) { + if (b->get_button_index() == MOUSE_BUTTON_LEFT) { if (get_item_at_position(b->get_position()) == nullptr && !b->get_shift() && !b->get_control() && !b->get_command()) { emit_signal("nothing_selected"); } @@ -2860,7 +2890,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } break; - case BUTTON_WHEEL_UP: { + case MOUSE_BUTTON_WHEEL_UP: { double prev_value = v_scroll->get_value(); v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * b->get_factor() / 8); if (v_scroll->get_value() != prev_value) { @@ -2868,7 +2898,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) { } } break; - case BUTTON_WHEEL_DOWN: { + case MOUSE_BUTTON_WHEEL_DOWN: { double prev_value = v_scroll->get_value(); v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * b->get_factor() / 8); if (v_scroll->get_value() != prev_value) { @@ -2930,7 +2960,7 @@ bool Tree::edit_selected() { popup_menu->clear(); for (int i = 0; i < c.text.get_slice_count(","); i++) { String s2 = c.text.get_slicec(',', i); - popup_menu->add_item(s2.get_slicec(':', 0), s2.get_slicec(':', 1).empty() ? i : s2.get_slicec(':', 1).to_int()); + popup_menu->add_item(s2.get_slicec(':', 0), s2.get_slicec(':', 1).is_empty() ? i : s2.get_slicec(':', 1).to_int()); } popup_menu->set_size(Size2(rect.size.width, 0)); @@ -3005,8 +3035,8 @@ void Tree::update_scrollbars() { Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - v_scroll->set_begin(Point2(size.width - vmin.width, cache.bg->get_margin(MARGIN_TOP))); - v_scroll->set_end(Point2(size.width, size.height - cache.bg->get_margin(MARGIN_TOP) - cache.bg->get_margin(MARGIN_BOTTOM))); + v_scroll->set_begin(Point2(size.width - vmin.width, cache.bg->get_margin(SIDE_TOP))); + v_scroll->set_end(Point2(size.width, size.height - cache.bg->get_margin(SIDE_TOP) - cache.bg->get_margin(SIDE_BOTTOM))); h_scroll->set_begin(Point2(0, size.height - hmin.height)); h_scroll->set_end(Point2(size.width - vmin.width, size.height)); @@ -3143,6 +3173,8 @@ void Tree::_notification(int p_what) { Ref<StyleBox> bg = cache.bg; Ref<StyleBox> bg_focus = get_theme_stylebox("bg_focus"); + Color font_outline_color = get_theme_color("font_outline_color"); + int outline_size = get_theme_constant("outline_size"); Point2 draw_ofs; draw_ofs += bg->get_offset(); @@ -3166,11 +3198,11 @@ void Tree::_notification(int p_what) { if (show_column_titles) { //title buttons - int ofs2 = cache.bg->get_margin(MARGIN_LEFT); + int ofs2 = cache.bg->get_margin(SIDE_LEFT); for (int i = 0; i < columns.size(); i++) { Ref<StyleBox> sb = (cache.click_type == Cache::CLICK_TITLE && cache.click_index == i) ? cache.title_button_pressed : ((cache.hover_type == Cache::CLICK_TITLE && cache.hover_index == i) ? cache.title_button_hover : cache.title_button); Ref<Font> f = cache.tb_font; - Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(MARGIN_TOP), get_column_width(i), tbh); + Rect2 tbrect = Rect2(ofs2 - cache.offset.x, bg->get_margin(SIDE_TOP), get_column_width(i), tbh); if (is_layout_rtl()) { tbrect.position.x = get_size().width - tbrect.size.x - tbrect.position.x; } @@ -3179,7 +3211,12 @@ void Tree::_notification(int p_what) { //text int clip_w = tbrect.size.width - sb->get_minimum_size().width; columns.write[i].text_buf->set_width(clip_w); - columns[i].text_buf->draw(ci, tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2), cache.title_button_color); + + Vector2 text_pos = tbrect.position + Point2i(sb->get_offset().x + (tbrect.size.width - columns[i].text_buf->get_size().x) / 2, (tbrect.size.height - columns[i].text_buf->get_size().y) / 2); + if (outline_size > 0 && font_outline_color.a > 0) { + columns[i].text_buf->draw_outline(ci, text_pos, outline_size, font_outline_color); + } + columns[i].text_buf->draw(ci, text_pos, cache.title_button_color); } } } @@ -3315,6 +3352,9 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { //emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select selected_col = p_column; + if (!selected_item) { + selected_item = p_item; + } } else { select_single_item(p_item, root, p_column); } @@ -3322,6 +3362,14 @@ void Tree::item_selected(int p_column, TreeItem *p_item) { } void Tree::item_deselected(int p_column, TreeItem *p_item) { + if (selected_item == p_item) { + selected_item = nullptr; + + if (selected_col == p_column) { + selected_col = -1; + } + } + if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) { p_item->cells.write[p_column].selected = false; } @@ -3468,9 +3516,13 @@ int Tree::get_column_width(int p_column) const { return columns[p_column].min_width; } + int expand_area = get_size().width; + Ref<StyleBox> bg = cache.bg; - int expand_area = get_size().width - (bg->get_margin(MARGIN_LEFT) + bg->get_margin(MARGIN_RIGHT)); + if (bg.is_valid()) { + expand_area -= bg->get_margin(SIDE_LEFT) + bg->get_margin(SIDE_RIGHT); + } if (v_scroll->is_visible_in_tree()) { expand_area -= v_scroll->get_combined_minimum_size().width; @@ -4149,6 +4201,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_edited"), &Tree::get_edited); ClassDB::bind_method(D_METHOD("get_edited_column"), &Tree::get_edited_column); + ClassDB::bind_method(D_METHOD("edit_selected"), &Tree::edit_selected); ClassDB::bind_method(D_METHOD("get_custom_popup_rect"), &Tree::get_custom_popup_rect); ClassDB::bind_method(D_METHOD("get_item_area_rect", "item", "column"), &Tree::_get_item_rect, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("get_item_at_position", "position"), &Tree::get_item_at_position); @@ -4174,6 +4227,7 @@ void Tree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_column_title_language", "column"), &Tree::get_column_title_language); ClassDB::bind_method(D_METHOD("get_scroll"), &Tree::get_scroll); + ClassDB::bind_method(D_METHOD("scroll_to_item", "item"), &Tree::_scroll_to_item); ClassDB::bind_method(D_METHOD("set_hide_folding", "hide"), &Tree::set_hide_folding); ClassDB::bind_method(D_METHOD("is_folding_hidden"), &Tree::is_folding_hidden); @@ -4223,19 +4277,8 @@ void Tree::_bind_methods() { } Tree::Tree() { - selected_col = 0; columns.resize(1); - selected_item = nullptr; - edited_item = nullptr; - selected_col = -1; - edited_col = -1; - hide_root = false; - select_mode = SELECT_SINGLE; - root = nullptr; - popup_menu = nullptr; - popup_edited_item = nullptr; - text_editor = nullptr; set_focus_mode(FOCUS_ALL); popup_menu = memnew(PopupMenu); @@ -4249,7 +4292,7 @@ Tree::Tree() { popup_editor_vb = memnew(VBoxContainer); popup_editor->add_child(popup_editor_vb); popup_editor_vb->add_theme_constant_override("separation", 0); - popup_editor_vb->set_anchors_and_margins_preset(PRESET_WIDE); + popup_editor_vb->set_anchors_and_offsets_preset(PRESET_WIDE); text_editor = memnew(LineEdit); popup_editor_vb->add_child(text_editor); text_editor->set_v_size_flags(SIZE_EXPAND_FILL); @@ -4279,50 +4322,9 @@ Tree::Tree() { set_notify_transform(true); - updating_value_editor = false; - pressed_button = -1; - show_column_titles = false; - - cache.click_type = Cache::CLICK_NONE; - cache.hover_type = Cache::CLICK_NONE; - cache.hover_index = -1; - cache.click_index = -1; - cache.click_id = -1; - cache.click_item = nullptr; - cache.click_column = 0; - cache.hover_cell = -1; - last_keypress = 0; - focus_in_id = 0; - - blocked = 0; - - cursor_can_exit_tree = true; set_mouse_filter(MOUSE_FILTER_STOP); - drag_speed = 0; - drag_touching = false; - drag_touching_deaccel = false; - pressing_for_editor = false; - range_drag_enabled = false; - - hide_folding = false; - - drop_mode_flags = 0; - drop_mode_over = nullptr; - drop_mode_section = 0; - single_select_defer = nullptr; - - scrolling = false; - allow_rmb_select = false; - force_edit_checkbox_only_on_checkbox = false; - set_clip_contents(true); - - cache.hover_item = nullptr; - cache.hover_cell = -1; - - allow_reselect = false; - propagate_mouse_activated = false; } Tree::~Tree() { diff --git a/scene/gui/tree.h b/scene/gui/tree.h index 82422b8be3..d1407e24d4 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -62,7 +62,7 @@ private: friend class Tree; struct Cell { - TreeCellMode mode; + TreeCellMode mode = TreeItem::CELL_MODE_STRING; Ref<Texture2D> icon; Rect2i icon_region; @@ -74,24 +74,27 @@ private: Control::StructuredTextParser st_parser = Control::STRUCTURED_TEXT_DEFAULT; Array st_args; Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; - bool dirty; - double min, max, step, val; - int icon_max_w; - bool expr; - bool checked; - bool editable; - bool selected; - bool selectable; - bool custom_color; + bool dirty = true; + double min = 0.0; + double max = 100.0; + double step = 1.0; + double val = 0.0; + int icon_max_w = 0; + bool expr = false; + bool checked = false; + bool editable = false; + bool selected = false; + bool selectable = true; + bool custom_color = false; Color color; - bool custom_bg_color; - bool custom_bg_outline; + bool custom_bg_color = false; + bool custom_bg_outline = false; Color bg_color; - bool custom_button; - bool expand_right; - Color icon_color; + bool custom_button = false; + bool expand_right = false; + Color icon_color = Color(1, 1, 1); - TextAlign text_align; + TextAlign text_align = ALIGN_LEFT; Variant meta; String tooltip; @@ -100,42 +103,17 @@ private: StringName custom_draw_callback; struct Button { - int id; - bool disabled; + int id = 0; + bool disabled = false; Ref<Texture2D> texture; - Color color; + Color color = Color(1, 1, 1, 1); String tooltip; - Button() { - id = 0; - disabled = false; - color = Color(1, 1, 1, 1); - tooltip = ""; - } }; Vector<Button> buttons; Cell() { text_buf.instance(); - dirty = true; - custom_draw_obj = ObjectID(); - custom_button = false; - mode = TreeItem::CELL_MODE_STRING; - min = 0; - max = 100; - step = 1; - val = 0; - checked = false; - editable = false; - selected = false; - selectable = true; - custom_color = false; - custom_bg_color = false; - expr = false; - icon_max_w = 0; - text_align = ALIGN_LEFT; - expand_right = false; - icon_color = Color(1, 1, 1); } Size2 get_icon_size() const; @@ -251,6 +229,8 @@ public: void set_collapsed(bool p_collapsed); bool is_collapsed(); + void uncollapse_tree(); + void set_custom_minimum_height(int p_height); int get_custom_minimum_height() const; @@ -332,46 +312,46 @@ public: private: friend class TreeItem; - TreeItem *root; - TreeItem *popup_edited_item; - TreeItem *selected_item; - TreeItem *edited_item; + TreeItem *root = nullptr; + TreeItem *popup_edited_item = nullptr; + TreeItem *selected_item = nullptr; + TreeItem *edited_item = nullptr; - TreeItem *drop_mode_over; - int drop_mode_section; + TreeItem *drop_mode_over = nullptr; + int drop_mode_section = 0; - TreeItem *single_select_defer; - int single_select_defer_column; + TreeItem *single_select_defer = nullptr; + int single_select_defer_column = 0; - int pressed_button; - bool pressing_for_editor; + int pressed_button = -1; + bool pressing_for_editor = false; String pressing_for_editor_text; Vector2 pressing_pos; Rect2 pressing_item_rect; - float range_drag_base; - bool range_drag_enabled; + float range_drag_base = 0.0; + bool range_drag_enabled = false; Vector2 range_drag_capture_pos; - bool propagate_mouse_activated; + bool propagate_mouse_activated = false; //TreeItem *cursor_item; //int cursor_column; Rect2 custom_popup_rect; - int edited_col; - int selected_col; - int popup_edited_item_col; - bool hide_root; - SelectMode select_mode; + int edited_col = -1; + int selected_col = -1; + int popup_edited_item_col = -1; + bool hide_root = false; + SelectMode select_mode = SELECT_SINGLE; - int blocked; + int blocked = 0; - int drop_mode_flags; + int drop_mode_flags = 0; struct ColumnInfo { - int min_width; - bool expand; + int min_width = 1; + bool expand = true; String title; Ref<TextLine> text_buf; Dictionary opentype_features; @@ -379,27 +359,25 @@ private: Control::TextDirection text_direction = Control::TEXT_DIRECTION_INHERITED; ColumnInfo() { text_buf.instance(); - min_width = 1; - expand = true; } }; - bool show_column_titles; + bool show_column_titles = false; VBoxContainer *popup_editor_vb; Popup *popup_editor; - LineEdit *text_editor; + LineEdit *text_editor = nullptr; HSlider *value_editor; - bool updating_value_editor; - uint64_t focus_in_id; - PopupMenu *popup_menu; + bool updating_value_editor = false; + uint64_t focus_in_id = 0; + PopupMenu *popup_menu = nullptr; Vector<ColumnInfo> columns; Timer *range_click_timer; - TreeItem *range_item_last; - bool range_up_last; + TreeItem *range_item_last = nullptr; + bool range_up_last = false; void _range_click_timeout(); int compute_item_height(TreeItem *p_item) const; @@ -409,7 +387,7 @@ private: void update_item_cell(TreeItem *p_item, int p_col); void update_item_cache(TreeItem *p_item); //void draw_item_text(String p_text,const Ref<Texture2D>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color); - void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color); + void draw_item_rect(TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color, int p_ol_size, const Color &p_ol_color); int draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 &p_draw_size, TreeItem *p_item); void select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_col, TreeItem *p_prev = nullptr, bool *r_in_range = nullptr, bool p_force_deselect = false); int propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool p_doubleclick, TreeItem *p_item, int p_button, const Ref<InputEventWithModifiers> &p_mod); @@ -434,8 +412,8 @@ private: struct Cache { Ref<Font> font; Ref<Font> tb_font; - int font_size; - int tb_font_size; + int font_size = 0; + int tb_font_size = 0; Ref<StyleBox> bg; Ref<StyleBox> selected; Ref<StyleBox> selected_focus; @@ -459,21 +437,21 @@ private: Ref<Texture2D> updown; Color font_color; - Color font_color_selected; + Color font_selected_color; Color guide_color; Color drop_position_color; Color relationship_line_color; Color custom_button_font_highlight; - int hseparation; - int vseparation; - int item_margin; - int button_margin; + int hseparation = 0; + int vseparation = 0; + int item_margin = 0; + int button_margin = 0; Point2 offset; - int draw_relationship_lines; - int draw_guides; - int scroll_border; - int scroll_speed; + int draw_relationship_lines = 0; + int draw_guides = 0; + int scroll_border = 0; + int scroll_speed = 0; enum ClickType { CLICK_NONE, @@ -482,17 +460,17 @@ private: }; - ClickType click_type; - ClickType hover_type; - int click_index; - int click_id; - TreeItem *click_item; - int click_column; - int hover_index; + ClickType click_type = Cache::CLICK_NONE; + ClickType hover_type = Cache::CLICK_NONE; + int click_index = -1; + int click_id = -1; + TreeItem *click_item = nullptr; + int click_column = 0; + int hover_index = -1; Point2 click_pos; - TreeItem *hover_item; - int hover_cell; + TreeItem *hover_item = nullptr; + int hover_cell = -1; Point2i text_editor_position; @@ -510,9 +488,9 @@ private: Rect2 search_item_rect(TreeItem *p_from, TreeItem *p_item); //Rect2 get_item_rect(TreeItem *p_item); - uint64_t last_keypress; + uint64_t last_keypress = 0; String incr_search; - bool cursor_can_exit_tree; + bool cursor_can_exit_tree = true; void _do_incr_search(const String &p_add); TreeItem *_search_item_text(TreeItem *p_at, const String &p_find, int *r_col, bool p_selectable, bool p_backwards = false); @@ -526,21 +504,21 @@ private: float last_drag_time; float time_since_motion;*/ - float drag_speed; - float drag_from; - float drag_accum; + float drag_speed = 0.0; + float drag_from = 0.0; + float drag_accum = 0.0; Vector2 last_speed; - bool drag_touching; - bool drag_touching_deaccel; - bool click_handled; - bool allow_rmb_select; - bool scrolling; + bool drag_touching = false; + bool drag_touching_deaccel = false; + bool click_handled = false; + bool allow_rmb_select = false; + bool scrolling = false; - bool allow_reselect; + bool allow_reselect = false; - bool force_edit_checkbox_only_on_checkbox; + bool force_edit_checkbox_only_on_checkbox = false; - bool hide_folding; + bool hide_folding = false; int _count_selected_items(TreeItem *p_from) const; void _go_left(); @@ -564,6 +542,10 @@ protected: return get_item_rect(Object::cast_to<TreeItem>(p_item), p_column); } + void _scroll_to_item(Object *p_item) { + scroll_to_item(Object::cast_to<TreeItem>(p_item)); + } + public: virtual String get_tooltip(const Point2 &p_pos) const override; diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index e118cb0d8d..0590ae2415 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -462,25 +462,7 @@ void VideoPlayer::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); } -VideoPlayer::VideoPlayer() { - volume = 1; - loops = false; - paused = false; - autoplay = false; - expand = true; - - audio_track = 0; - bus_index = 0; - - buffering_ms = 500; - - // internal_stream.player=this; - // stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); - last_audio_time = 0; - - wait_resampler = 0; - wait_resampler_limit = 2; -}; +VideoPlayer::VideoPlayer() {} VideoPlayer::~VideoPlayer() { // if (stream_rid.is_valid()) diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h index 573aec5a2c..0edad296a1 100644 --- a/scene/gui/video_player.h +++ b/scene/gui/video_player.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,8 +41,8 @@ class VideoPlayer : public Control { struct Output { AudioFrame vol; - int bus_index; - Viewport *viewport; //pointer only used for reference to previous mix + int bus_index = 0; + Viewport *viewport = nullptr; //pointer only used for reference to previous mix }; Ref<VideoStreamPlayback> playback; Ref<VideoStream> stream; @@ -56,17 +56,18 @@ class VideoPlayer : public Control { AudioRBResampler resampler; Vector<AudioFrame> mix_buffer; - int wait_resampler, wait_resampler_limit; - - bool paused; - bool autoplay; - float volume; - double last_audio_time; - bool expand; - bool loops; - int buffering_ms; - int audio_track; - int bus_index; + int wait_resampler = 0; + int wait_resampler_limit = 2; + + bool paused = false; + bool autoplay = false; + float volume = 1.0; + double last_audio_time = 0.0; + bool expand = true; + bool loops = false; + int buffering_ms = 500; + int audio_track = 0; + int bus_index = 0; StringName bus; diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 8babb1460f..55529517f1 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -203,7 +203,7 @@ CanvasItemMaterial::LightMode CanvasItemMaterial::get_light_mode() const { void CanvasItemMaterial::set_particles_animation(bool p_particles_anim) { particles_animation = p_particles_anim; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool CanvasItemMaterial::get_particles_animation() const { @@ -387,7 +387,6 @@ void CanvasItem::show() { } _propagate_visibility_changed(true); - _change_notify("visible"); } void CanvasItem::hide() { @@ -403,7 +402,6 @@ void CanvasItem::hide() { } _propagate_visibility_changed(false); - _change_notify("visible"); } CanvasItem *CanvasItem::current_item_drawn = nullptr; @@ -731,13 +729,13 @@ void CanvasItem::item_rect_changed(bool p_size_changed) { emit_signal(SceneStringNames::get_singleton()->item_rect_changed); } -void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { +void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width); } -void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) { +void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width, bool p_antialiased) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); Vector<Color> colors; @@ -745,25 +743,25 @@ void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_co RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased); } -void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { +void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width, bool p_antialiased) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased); } -void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) { +void CanvasItem::draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width, bool p_antialiased) { Vector<Point2> points; points.resize(p_point_count); - const float delta_angle = p_end_angle - p_start_angle; + const real_t delta_angle = p_end_angle - p_start_angle; for (int i = 0; i < p_point_count; i++) { - float theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle; + real_t theta = (i / (p_point_count - 1.0f)) * delta_angle + p_start_angle; points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius); } draw_polyline(points, p_color, p_width, p_antialiased); } -void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) { +void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); Vector<Color> colors; @@ -771,13 +769,13 @@ void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_c RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, colors, p_width); } -void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { +void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RenderingServer::get_singleton()->canvas_item_add_multiline(canvas_item, p_points, p_colors, p_width); } -void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, float p_width) { +void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled, real_t p_width) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); if (p_filled) { @@ -789,7 +787,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil } else { // Thick lines are offset depending on their width to avoid partial overlapping. // Thin lines don't require an offset, so don't apply one in this case - float offset; + real_t offset; if (p_width >= 2) { offset = p_width / 2.0; } else { @@ -823,7 +821,7 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil } } -void CanvasItem::draw_circle(const Point2 &p_pos, float p_radius, const Color &p_color) { +void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color); @@ -858,14 +856,14 @@ 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) { +void CanvasItem::draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture, real_t 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(); 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) { +void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); Transform2D xform(p_rot, p_offset); @@ -909,19 +907,19 @@ void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Tex 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, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { +void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_font.is_null()); p_font->draw_string(canvas_item, p_pos, p_text, p_align, p_width, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags); } -void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { +void CanvasItem::draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align, real_t p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND(p_font.is_null()); p_font->draw_multiline_string(canvas_item, p_pos, p_text, p_align, p_width, p_max_lines, p_size, p_modulate, p_outline_size, p_outline_modulate, p_flags); } -float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const { +real_t CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate) const { ERR_FAIL_COND_V_MSG(!drawing, 0.f, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); ERR_FAIL_COND_V(p_font.is_null(), 0.f); ERR_FAIL_COND_V(p_char.length() != 1, 0.f); @@ -1035,7 +1033,7 @@ void CanvasItem::set_material(const Ref<Material> &p_material) { rid = material->get_rid(); } RS::get_singleton()->canvas_item_set_material(canvas_item, rid); - _change_notify(); //properties for material exposed + notify_property_list_changed(); //properties for material exposed } void CanvasItem::set_use_parent_material(bool p_use_parent_material) { @@ -1341,7 +1339,7 @@ void CanvasItem::set_texture_filter(TextureFilter p_texture_filter) { } texture_filter = p_texture_filter; _update_texture_filter_changed(true); - _change_notify(); + notify_property_list_changed(); } CanvasItem::TextureFilter CanvasItem::get_texture_filter() const { @@ -1381,7 +1379,7 @@ void CanvasItem::set_texture_repeat(TextureRepeat p_texture_repeat) { } texture_repeat = p_texture_repeat; _update_texture_repeat_changed(true); - _change_notify(); + notify_property_list_changed(); } void CanvasItem::set_clip_children(bool p_enabled) { @@ -1443,6 +1441,7 @@ void CanvasTexture::set_specular_texture(const Ref<Texture2D> &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; } @@ -1451,15 +1450,17 @@ 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) { +void CanvasTexture::set_specular_shininess(real_t p_shininess) { shininess = p_shininess; RS::get_singleton()->canvas_texture_set_shading_parameters(canvas_texture, specular, shininess); } -float CanvasTexture::get_specular_shininess() const { + +real_t CanvasTexture::get_specular_shininess() const { return shininess; } @@ -1510,9 +1511,9 @@ bool CanvasTexture::has_alpha() const { } } -Ref<Image> CanvasTexture::get_data() const { +Ref<Image> CanvasTexture::get_image() const { if (diffuse_texture.is_valid()) { - return diffuse_texture->get_data(); + return diffuse_texture->get_image(); } else { return Ref<Image>(); } diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 34268c1a78..1c64cafab8 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -90,7 +90,7 @@ private: struct ShaderData { RID shader; - int users; + int users = 0; }; static Map<MaterialKey, ShaderData> shader_map; @@ -149,7 +149,7 @@ public: static void finish_shaders(); static void flush_changes(); - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; virtual Shader::Mode get_shader_mode() const override; @@ -290,8 +290,8 @@ public: // Used to rotate the node virtual bool _edit_use_rotation() const { return false; }; - virtual void _edit_set_rotation(float p_rotation) {} - virtual float _edit_get_rotation() const { return 0.0; }; + virtual void _edit_set_rotation(real_t p_rotation) {} + virtual real_t _edit_get_rotation() const { return 0.0; }; // Used to resize/move the node virtual bool _edit_use_rect() const { return false; }; // MAYBE REPLACE BY A _edit_get_editmode() @@ -331,30 +331,30 @@ public: /* DRAWING API */ - void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0); - void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); - void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false); - void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false); - void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0); - 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_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0); + void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); + void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0, bool p_antialiased = false); + void draw_arc(const Vector2 &p_center, real_t p_radius, real_t p_start_angle, real_t p_end_angle, int p_point_count, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false); + void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, real_t p_width = 1.0); + void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, real_t p_width = 1.0); + void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = 1.0); + void draw_circle(const Point2 &p_pos, real_t 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)); 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); + void draw_primitive(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, Ref<Texture2D> p_texture = Ref<Texture2D>(), real_t 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 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, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; - void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, float p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; - float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const; + void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; + void draw_multiline_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, HAlign p_align = HALIGN_LEFT, real_t p_width = -1, int p_max_lines = -1, int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0), uint8_t p_flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND) const; + real_t draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", int p_size = -1, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, const Color &p_outline_modulate = Color(1, 1, 1, 0)) const; - void draw_set_transform(const Point2 &p_offset, float p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0)); + void draw_set_transform(const Point2 &p_offset, real_t p_rot = 0.0, const Size2 &p_scale = Size2(1.0, 1.0)); void draw_set_transform_matrix(const Transform2D &p_matrix); static CanvasItem *get_current_item_drawn(); @@ -437,7 +437,7 @@ class CanvasTexture : public Texture2D { Ref<Texture2D> normal_texture; Ref<Texture2D> specular_texture; Color specular = Color(1, 1, 1, 1); - float shininess = 1.0; + real_t shininess = 1.0; RID canvas_texture; @@ -460,8 +460,8 @@ public: 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_specular_shininess(real_t p_shininess); + real_t get_specular_shininess() const; void set_texture_filter(CanvasItem::TextureFilter p_filter); CanvasItem::TextureFilter get_texture_filter() const; @@ -475,7 +475,7 @@ public: 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 Ref<Image> get_image() const override; virtual RID get_rid() const override; diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 46cfb968f8..85d7edd64b 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -231,6 +231,7 @@ void CanvasLayer::set_follow_viewport(bool p_enable) { follow_viewport = p_enable; _update_follow_viewport(); + notify_property_list_changed(); } bool CanvasLayer::is_following_viewport() const { @@ -257,6 +258,12 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) { } } +void CanvasLayer::_validate_property(PropertyInfo &property) const { + if (!follow_viewport && property.name == "follow_viewport_scale") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer); ClassDB::bind_method(D_METHOD("get_layer"), &CanvasLayer::get_layer); @@ -303,17 +310,7 @@ void CanvasLayer::_bind_methods() { } CanvasLayer::CanvasLayer() { - vp = nullptr; - scale = Vector2(1, 1); - rot = 0; - locrotscale_dirty = false; - layer = 1; canvas = RS::get_singleton()->canvas_create(); - custom_viewport = nullptr; - - sort_index = 0; - follow_viewport = false; - follow_viewport_scale = 1.0; } CanvasLayer::~CanvasLayer() { diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 0c68b1ab69..899039340a 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,24 +38,24 @@ class Viewport; class CanvasLayer : public Node { GDCLASS(CanvasLayer, Node); - bool locrotscale_dirty; + bool locrotscale_dirty = false; Vector2 ofs; - Size2 scale; - real_t rot; - int layer; + Size2 scale = Vector2(1, 1); + real_t rot = 0.0; + int layer = 1; Transform2D transform; RID canvas; ObjectID custom_viewport_id; // to check validity - Viewport *custom_viewport; + Viewport *custom_viewport = nullptr; RID viewport; - Viewport *vp; + Viewport *vp = nullptr; - int sort_index; + int sort_index = 0; - bool follow_viewport; - float follow_viewport_scale; + bool follow_viewport = false; + float follow_viewport_scale = 1.0; void _update_xform(); void _update_locrotscale(); @@ -64,6 +64,7 @@ class CanvasLayer : public Node { protected: void _notification(int p_what); static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: void set_layer(int p_xform); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index f484d25dc1..e4ed5c6e6c 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -49,7 +49,7 @@ Error HTTPRequest::_parse_url(const String &p_url) { got_response = false; body_len = -1; body.resize(0); - downloaded = 0; + downloaded.set(0); redirections = 0; String url_lower = url.to_lower(); @@ -159,11 +159,11 @@ Error HTTPRequest::request_raw(const String &p_url, const Vector<String> &p_cust requesting = true; - if (use_threads) { - thread_done = false; - thread_request_quit = false; + if (use_threads.is_set()) { + thread_done.clear(); + thread_request_quit.clear(); client->set_blocking_mode(true); - thread = Thread::create(_thread_func, this); + thread.start(_thread_func, this); } else { client->set_blocking_mode(false); err = _request(); @@ -186,7 +186,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { if (err != OK) { hr->call_deferred("_request_done", RESULT_CANT_CONNECT, 0, PackedStringArray(), PackedByteArray()); } else { - while (!hr->thread_request_quit) { + while (!hr->thread_request_quit.is_set()) { bool exit = hr->_update_connection(); if (exit) { break; @@ -195,7 +195,7 @@ void HTTPRequest::_thread_func(void *p_userdata) { } } - hr->thread_done = true; + hr->thread_done.set(); } void HTTPRequest::cancel_request() { @@ -205,13 +205,11 @@ void HTTPRequest::cancel_request() { return; } - if (!use_threads) { + if (!use_threads.is_set()) { set_process_internal(false); } else { - thread_request_quit = true; - Thread::wait_to_finish(thread); - memdelete(thread); - thread = nullptr; + thread_request_quit.set(); + thread.wait_to_finish(); } if (file) { @@ -238,7 +236,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { List<String> rheaders; client->get_response_headers(&rheaders); response_headers.resize(0); - downloaded = 0; + downloaded.set(0); for (List<String>::Element *E = rheaders.front(); E; E = E->next()) { response_headers.push_back(E->get()); } @@ -278,7 +276,7 @@ bool HTTPRequest::_handle_response(bool *ret_value) { got_response = false; body_len = -1; body.resize(0); - downloaded = 0; + downloaded.set(0); redirections = new_redirs; *ret_value = false; return true; @@ -337,7 +335,7 @@ bool HTTPRequest::_update_connection() { call_deferred("_request_done", RESULT_CHUNKED_BODY_SIZE_MISMATCH, response_code, response_headers, PackedByteArray()); return true; - // Request migh have been done + // Request might have been done } else { // Did not request yet, do request @@ -389,9 +387,12 @@ bool HTTPRequest::_update_connection() { } client->poll(); + if (client->get_status() != HTTPClient::STATUS_BODY) { + return false; + } PackedByteArray chunk = client->read_response_body_chunk(); - downloaded += chunk.size(); + downloaded.add(chunk.size()); if (file) { const uint8_t *r = chunk.ptr(); @@ -404,19 +405,20 @@ bool HTTPRequest::_update_connection() { body.append_array(chunk); } - if (body_size_limit >= 0 && downloaded > body_size_limit) { + if (body_size_limit >= 0 && downloaded.get() > body_size_limit) { call_deferred("_request_done", RESULT_BODY_SIZE_LIMIT_EXCEEDED, response_code, response_headers, PackedByteArray()); return true; } if (body_len >= 0) { - if (downloaded == body_len) { + if (downloaded.get() == body_len) { call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); return true; } } else if (client->get_status() == HTTPClient::STATUS_DISCONNECTED) { // We read till EOF, with no errors. Request is done. call_deferred("_request_done", RESULT_SUCCESS, response_code, response_headers, body); + return true; } return false; @@ -480,7 +482,7 @@ void HTTPRequest::_request_done(int p_status, int p_code, const PackedStringArra void HTTPRequest::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (use_threads) { + if (use_threads.is_set()) { return; } bool done = _update_connection(); @@ -499,11 +501,11 @@ void HTTPRequest::_notification(int p_what) { void HTTPRequest::set_use_threads(bool p_use) { ERR_FAIL_COND(get_http_client_status() != HTTPClient::STATUS_DISCONNECTED); - use_threads = p_use; + use_threads.set_to(p_use); } bool HTTPRequest::is_using_threads() const { - return use_threads; + return use_threads.is_set(); } void HTTPRequest::set_accept_gzip(bool p_gzip) { @@ -557,7 +559,7 @@ int HTTPRequest::get_max_redirects() const { } int HTTPRequest::get_downloaded_bytes() const { - return downloaded; + return downloaded.get(); } int HTTPRequest::get_body_size() const { @@ -640,31 +642,11 @@ void HTTPRequest::_bind_methods() { } HTTPRequest::HTTPRequest() { - thread = nullptr; - - port = 80; - redirections = 0; - max_redirects = 8; - body_len = -1; - got_response = false; - validate_ssl = false; - use_ssl = false; - accept_gzip = true; - response_code = 0; - request_sent = false; - requesting = false; client.instance(); - use_threads = false; - thread_done = false; - downloaded = 0; - body_size_limit = -1; - file = nullptr; - timer = memnew(Timer); timer->set_one_shot(true); timer->connect("timeout", callable_mp(this, &HTTPRequest::_timeout)); add_child(timer); - timeout = 0; } HTTPRequest::~HTTPRequest() { diff --git a/scene/main/http_request.h b/scene/main/http_request.h index 2e8931120b..92b0ff28e9 100644 --- a/scene/main/http_request.h +++ b/scene/main/http_request.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,6 +34,7 @@ #include "core/io/http_client.h" #include "core/os/file_access.h" #include "core/os/thread.h" +#include "core/templates/safe_refcount.h" #include "node.h" #include "scene/main/timer.h" @@ -60,42 +61,42 @@ public: }; private: - bool requesting; + bool requesting = false; String request_string; String url; - int port; + int port = 80; Vector<String> headers; - bool validate_ssl; - bool use_ssl; + bool validate_ssl = false; + bool use_ssl = false; HTTPClient::Method method; Vector<uint8_t> request_data; - bool request_sent; + bool request_sent = false; Ref<HTTPClient> client; PackedByteArray body; - volatile bool use_threads; - bool accept_gzip; + SafeFlag use_threads; + bool accept_gzip = true; - bool got_response; - int response_code; + bool got_response = false; + int response_code = 0; Vector<String> response_headers; String download_to_file; - FileAccess *file; + FileAccess *file = nullptr; - int body_len; - volatile int downloaded; - int body_size_limit; + int body_len = -1; + SafeNumeric<int> downloaded; + int body_size_limit = -1; - int redirections; + int redirections = 0; bool _update_connection(); - int max_redirects; + int max_redirects = 8; - int timeout; + int timeout = 0; void _redirect_request(const String &p_new_url); @@ -107,10 +108,10 @@ private: 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; + SafeFlag thread_done; + SafeFlag thread_request_quit; - Thread *thread; + Thread thread; void _request_done(int p_status, int p_code, const PackedStringArray &p_headers, const PackedByteArray &p_data); static void _thread_func(void *p_userdata); diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp index ca8d5a2ca0..1661984e30 100644 --- a/scene/main/instance_placeholder.cpp +++ b/scene/main/instance_placeholder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h index ec1f8a9b09..fe20fc4760 100644 --- a/scene/main/instance_placeholder.h +++ b/scene/main/instance_placeholder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/main/node.cpp b/scene/main/node.cpp index e2df2860ea..933f67db68 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,7 +46,7 @@ #include <stdint.h> -VARIANT_ENUM_CAST(Node::PauseMode); +VARIANT_ENUM_CAST(Node::ProcessMode); int Node::orphan_node_count = 0; @@ -69,14 +69,14 @@ void Node::_notification(int p_notification) { ERR_FAIL_COND(!get_viewport()); ERR_FAIL_COND(!get_tree()); - if (data.pause_mode == PAUSE_MODE_INHERIT) { + if (data.process_mode == PROCESS_MODE_INHERIT) { if (data.parent) { - data.pause_owner = data.parent->data.pause_owner; + data.process_owner = data.parent->data.process_owner; } else { - data.pause_owner = nullptr; + data.process_owner = nullptr; } } else { - data.pause_owner = this; + data.process_owner = this; } if (data.input) { @@ -110,7 +110,7 @@ void Node::_notification(int p_notification) { remove_from_group("_vp_unhandled_key_input" + itos(get_viewport()->get_instance_id())); } - data.pause_owner = nullptr; + data.process_owner = nullptr; if (data.path_cache) { memdelete(data.path_cache); data.path_cache = nullptr; @@ -367,8 +367,6 @@ void Node::set_physics_process(bool p_process) { } else { remove_from_group("physics_process"); } - - _change_notify("physics_process"); } bool Node::is_physics_processing() const { @@ -387,52 +385,87 @@ void Node::set_physics_process_internal(bool p_process_internal) { } else { remove_from_group("physics_process_internal"); } - - _change_notify("physics_process_internal"); } bool Node::is_physics_processing_internal() const { return data.physics_process_internal; } -void Node::set_pause_mode(PauseMode p_mode) { - if (data.pause_mode == p_mode) { +void Node::set_process_mode(ProcessMode p_mode) { + if (data.process_mode == p_mode) { return; } - bool prev_inherits = data.pause_mode == PAUSE_MODE_INHERIT; - data.pause_mode = p_mode; if (!is_inside_tree()) { - return; //pointless - } - if ((data.pause_mode == PAUSE_MODE_INHERIT) == prev_inherits) { - return; ///nothing changed + data.process_mode = p_mode; + return; } - Node *owner = nullptr; + bool prev_can_process = can_process(); + + data.process_mode = p_mode; - if (data.pause_mode == PAUSE_MODE_INHERIT) { + if (data.process_mode == PROCESS_MODE_INHERIT) { if (data.parent) { - owner = data.parent->data.pause_owner; + data.process_owner = data.parent->data.owner; + } else { + data.process_owner = nullptr; } } else { - owner = this; + data.process_owner = this; + } + + bool next_can_process = can_process(); + + int pause_notification = 0; + + if (prev_can_process && !next_can_process) { + pause_notification = NOTIFICATION_PAUSED; + } else if (!prev_can_process && next_can_process) { + pause_notification = NOTIFICATION_UNPAUSED; } - _propagate_pause_owner(owner); + _propagate_process_owner(data.process_owner, pause_notification); +#ifdef TOOLS_ENABLED + // This is required for the editor to update the visibility of disabled nodes + // It's very expensive during runtime to change, so editor-only + if (Engine::get_singleton()->is_editor_hint()) { + get_tree()->emit_signal("tree_process_mode_changed"); + } +#endif } -Node::PauseMode Node::get_pause_mode() const { - return data.pause_mode; +void Node::_propagate_pause_notification(bool p_enable) { + bool prev_can_process = _can_process(!p_enable); + bool next_can_process = _can_process(p_enable); + + if (prev_can_process && !next_can_process) { + notification(NOTIFICATION_PAUSED); + } else if (!prev_can_process && next_can_process) { + notification(NOTIFICATION_UNPAUSED); + } + + for (int i = 0; i < data.children.size(); i++) { + data.children[i]->_propagate_pause_notification(p_enable); + } } -void Node::_propagate_pause_owner(Node *p_owner) { - if (this != p_owner && data.pause_mode != PAUSE_MODE_INHERIT) { - return; +Node::ProcessMode Node::get_process_mode() const { + return data.process_mode; +} + +void Node::_propagate_process_owner(Node *p_owner, int p_notification) { + data.process_owner = p_owner; + + if (p_notification != 0) { + notification(p_notification); } - data.pause_owner = p_owner; + for (int i = 0; i < data.children.size(); i++) { - data.children[i]->_propagate_pause_owner(p_owner); + Node *c = data.children[i]; + if (c->data.process_mode == PROCESS_MODE_INHERIT) { + c->_propagate_process_owner(p_owner, p_notification); + } } } @@ -466,7 +499,7 @@ uint16_t Node::rpc_config(const StringName &p_method, MultiplayerAPI::RPCMode p_ nd.name = p_method; nd.mode = p_mode; data.rpc_methods.push_back(nd); - return ((uint16_t)data.rpc_properties.size() - 1) | (1 << 15); + return ((uint16_t)data.rpc_methods.size() - 1) | (1 << 15); } else { int c_mid = (~(1 << 15)) & mid; data.rpc_methods.write[c_mid].mode = p_mode; @@ -555,7 +588,7 @@ Variant Node::_rpc_bind(const Variant **p_args, int p_argcount, Callable::CallEr return Variant(); } - if (p_args[0]->get_type() != Variant::STRING) { + if (p_args[0]->get_type() != Variant::STRING_NAME) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -584,7 +617,7 @@ Variant Node::_rpc_id_bind(const Variant **p_args, int p_argcount, Callable::Cal return Variant(); } - if (p_args[1]->get_type() != Variant::STRING) { + if (p_args[1]->get_type() != Variant::STRING_NAME) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; @@ -607,7 +640,7 @@ Variant Node::_rpc_unreliable_bind(const Variant **p_args, int p_argcount, Calla return Variant(); } - if (p_args[0]->get_type() != Variant::STRING) { + if (p_args[0]->get_type() != Variant::STRING_NAME) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::STRING; @@ -636,7 +669,7 @@ Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Ca return Variant(); } - if (p_args[1]->get_type() != Variant::STRING) { + if (p_args[1]->get_type() != Variant::STRING_NAME) { r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 1; r_error.expected = Variant::STRING; @@ -797,9 +830,9 @@ bool Node::can_process_notification(int p_what) const { case NOTIFICATION_PHYSICS_PROCESS: return data.physics_process; case NOTIFICATION_PROCESS: - return data.idle_process; + return data.process; case NOTIFICATION_INTERNAL_PROCESS: - return data.idle_process_internal; + return data.process_internal; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: return data.physics_process_internal; } @@ -809,30 +842,33 @@ bool Node::can_process_notification(int p_what) const { bool Node::can_process() const { ERR_FAIL_COND_V(!is_inside_tree(), false); + return _can_process(get_tree()->is_paused()); +} - if (get_tree()->is_paused()) { - if (data.pause_mode == PAUSE_MODE_STOP) { - return false; - } - if (data.pause_mode == PAUSE_MODE_PROCESS) { - return true; - } - if (data.pause_mode == PAUSE_MODE_INHERIT) { - if (!data.pause_owner) { - return false; //clearly no pause owner by default - } - - if (data.pause_owner->data.pause_mode == PAUSE_MODE_PROCESS) { - return true; - } +bool Node::_can_process(bool p_paused) const { + ProcessMode process_mode; - if (data.pause_owner->data.pause_mode == PAUSE_MODE_STOP) { - return false; - } + if (data.process_mode == PROCESS_MODE_INHERIT) { + if (!data.process_owner) { + process_mode = PROCESS_MODE_PAUSABLE; + } else { + process_mode = data.process_owner->data.process_mode; } + } else { + process_mode = data.process_mode; } - return true; + if (process_mode == PROCESS_MODE_DISABLED) { + return false; + } else if (process_mode == PROCESS_MODE_ALWAYS) { + return true; + } + + if (p_paused) { + return process_mode == PROCESS_MODE_WHEN_PAUSED; + } else { + return process_mode == PROCESS_MODE_PAUSABLE; + } } float Node::get_physics_process_delta_time() const { @@ -845,50 +881,46 @@ float Node::get_physics_process_delta_time() const { float Node::get_process_delta_time() const { if (data.tree) { - return data.tree->get_idle_process_time(); + return data.tree->get_process_time(); } else { return 0; } } -void Node::set_process(bool p_idle_process) { - if (data.idle_process == p_idle_process) { +void Node::set_process(bool p_process) { + if (data.process == p_process) { return; } - data.idle_process = p_idle_process; + data.process = p_process; - if (data.idle_process) { - add_to_group("idle_process", false); + if (data.process) { + add_to_group("process", false); } else { - remove_from_group("idle_process"); + remove_from_group("process"); } - - _change_notify("idle_process"); } bool Node::is_processing() const { - return data.idle_process; + return data.process; } -void Node::set_process_internal(bool p_idle_process_internal) { - if (data.idle_process_internal == p_idle_process_internal) { +void Node::set_process_internal(bool p_process_internal) { + if (data.process_internal == p_process_internal) { return; } - data.idle_process_internal = p_idle_process_internal; + data.process_internal = p_process_internal; - if (data.idle_process_internal) { - add_to_group("idle_process_internal", false); + if (data.process_internal) { + add_to_group("process_internal", false); } else { - remove_from_group("idle_process_internal"); + remove_from_group("process_internal"); } - - _change_notify("idle_process_internal"); } bool Node::is_processing_internal() const { - return data.idle_process_internal; + return data.process_internal; } void Node::set_process_priority(int p_priority) { @@ -900,11 +932,11 @@ void Node::set_process_priority(int p_priority) { } if (is_processing()) { - data.tree->make_group_changed("idle_process"); + data.tree->make_group_changed("process"); } if (is_processing_internal()) { - data.tree->make_group_changed("idle_process_internal"); + data.tree->make_group_changed("process_internal"); } if (is_physics_processing()) { @@ -989,22 +1021,8 @@ void Node::_set_name_nocheck(const StringName &p_name) { data.name = p_name; } -String Node::invalid_character = ". : @ / \""; - -bool Node::_validate_node_name(String &p_name) { - String name = p_name; - Vector<String> chars = Node::invalid_character.split(" "); - for (int i = 0; i < chars.size(); i++) { - name = name.replace(chars[i], ""); - } - bool is_valid = name == p_name; - p_name = name; - return is_valid; -} - void Node::set_name(const String &p_name) { - String name = p_name; - _validate_node_name(name); + String name = p_name.validate_node_name(); ERR_FAIL_COND(name == ""); data.name = name; @@ -1112,11 +1130,11 @@ String increase_numeric_string(const String &s) { void Node::_generate_serial_child_name(const Node *p_child, StringName &name) const { if (name == StringName()) { - //no name and a new nade is needed, create one. + //no name and a new name is needed, create one. name = p_child->get_class(); // Adjust casing according to project setting. The current type name is expected to be in PascalCase. - switch (ProjectSettings::get_singleton()->get("node/name_casing").operator int()) { + switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_casing").operator int()) { case NAME_CASING_PASCAL_CASE: break; case NAME_CASING_CAMEL_CASE: { @@ -1138,7 +1156,7 @@ void Node::_generate_serial_child_name(const Node *p_child, StringName &name) co bool exists = false; for (int i = 0; i < cc; i++) { - if (children_ptr[i] == p_child) { //exclude self in renaming if its already a child + if (children_ptr[i] == p_child) { //exclude self in renaming if it's already a child continue; } if (children_ptr[i]->data.name == name) { @@ -1410,7 +1428,15 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { Node *Node::get_node(const NodePath &p_path) const { Node *node = get_node_or_null(p_path); - ERR_FAIL_COND_V_MSG(!node, nullptr, "Node not found: " + p_path + "."); + + if (p_path.is_absolute()) { + ERR_FAIL_COND_V_MSG(!node, nullptr, + vformat(R"(Node not found: "%s" (absolute path attempted from "%s").)", p_path, get_path())); + } else { + ERR_FAIL_COND_V_MSG(!node, nullptr, + vformat(R"(Node not found: "%s" (relative to "%s").)", p_path, get_path())); + } + return node; } @@ -1887,7 +1913,7 @@ void Node::remove_and_skip() { } } - while (!children.empty()) { + while (!children.is_empty()) { Node *c_node = children.front()->get(); data.parent->add_child(c_node); c_node->_propagate_replace_owner(nullptr, new_owner); @@ -1906,46 +1932,49 @@ String Node::get_filename() const { } void Node::set_editor_description(const String &p_editor_description) { - set_meta("_editor_description_", p_editor_description); + data.editor_description = p_editor_description; } String Node::get_editor_description() const { - if (has_meta("_editor_description_")) { - return get_meta("_editor_description_"); - } else { - return ""; - } + return data.editor_description; } void Node::set_editable_instance(Node *p_node, bool p_editable) { ERR_FAIL_NULL(p_node); ERR_FAIL_COND(!is_a_parent_of(p_node)); - NodePath p = get_path_to(p_node); if (!p_editable) { - data.editable_instances.erase(p); + p_node->data.editable_instance = false; // Avoid this flag being needlessly saved; - // also give more visual feedback if editable children is re-enabled + // also give more visual feedback if editable children are re-enabled set_display_folded(false); } else { - data.editable_instances[p] = true; + p_node->data.editable_instance = true; } } bool Node::is_editable_instance(const Node *p_node) const { if (!p_node) { - return false; //easier, null is never editable :) + return false; // Easier, null is never editable. :) } ERR_FAIL_COND_V(!is_a_parent_of(p_node), false); - NodePath p = get_path_to(p_node); - return data.editable_instances.has(p); + return p_node->data.editable_instance; } -void Node::set_editable_instances(const HashMap<NodePath, int> &p_editable_instances) { - data.editable_instances = p_editable_instances; -} +Node *Node::get_deepest_editable_node(Node *p_start_node) const { + ERR_FAIL_NULL_V(p_start_node, nullptr); + ERR_FAIL_COND_V(!is_a_parent_of(p_start_node), p_start_node); + + Node const *iterated_item = p_start_node; + Node *node = p_start_node; + + while (iterated_item->get_owner() && iterated_item->get_owner() != this) { + if (!is_editable_instance(iterated_item->get_owner())) + node = iterated_item->get_owner(); + + iterated_item = iterated_item->get_owner(); + } -HashMap<NodePath, int> Node::get_editable_instances() const { - return data.editable_instances; + return node; } void Node::set_scene_instance_state(const Ref<SceneState> &p_state) { @@ -2009,6 +2038,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const if (get_filename() != "") { //an instance node->set_filename(get_filename()); + node->data.editable_instance = data.editable_instance; } StringName script_property_name = CoreStringNames::get_singleton()->_script; @@ -2021,19 +2051,26 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const // Since nodes in the instanced hierarchy won't be duplicated explicitly, we need to make an inventory // of all the nodes in the tree of the instanced scene in order to transfer the values of the properties + Vector<const Node *> instance_roots; + instance_roots.push_back(this); + for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) { for (int i = 0; i < N->get()->get_child_count(); ++i) { Node *descendant = N->get()->get_child(i); // Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later // but remember non-instanced nodes that are hidden below instanced ones - if (descendant->data.owner != this) { - if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this && descendant->data.owner != descendant->get_parent()) { + if (!instance_roots.has(descendant->get_owner())) { + if (descendant->get_parent() && descendant->get_parent() != this && descendant->data.owner != descendant->get_parent()) { hidden_roots.push_back(descendant); } continue; } node_tree.push_back(descendant); + + if (descendant->get_filename() != "" && instance_roots.has(descendant->get_owner())) { + instance_roots.push_back(descendant); + } } } } @@ -2156,8 +2193,17 @@ Node *Node::duplicate(int p_flags) const { #ifdef TOOLS_ENABLED Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const { + return duplicate_from_editor(r_duplimap, Map<RES, RES>()); +} + +Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const { Node *dupe = _duplicate(DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS | DUPLICATE_USE_INSTANCING | DUPLICATE_FROM_EDITOR, &r_duplimap); + // This is used by SceneTreeDock's paste functionality. When pasting to foreign scene, resources are duplicated. + if (!p_resource_remap.is_empty()) { + remap_node_resources(dupe, p_resource_remap); + } + // Duplication of signals must happen after all the node descendants have been copied, // because re-targeting of connections from some descendant to another is not possible // if the emitter node comes later in tree order than the receiver @@ -2165,75 +2211,55 @@ Node *Node::duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const { return dupe; } -#endif -void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const { - if (get_owner() != get_parent()->get_owner()) { - return; - } +void Node::remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const { + List<PropertyInfo> props; + p_node->get_property_list(&props); - Node *node = nullptr; - - if (get_filename() != "") { - Ref<PackedScene> res = ResourceLoader::load(get_filename()); - ERR_FAIL_COND_MSG(res.is_null(), "Cannot load scene: " + get_filename()); - node = res->instance(); - ERR_FAIL_COND(!node); - } else { - Object *obj = ClassDB::instance(get_class()); - ERR_FAIL_COND_MSG(!obj, "Node: Could not duplicate: " + String(get_class()) + "."); - node = Object::cast_to<Node>(obj); - if (!node) { - memdelete(obj); - ERR_FAIL_MSG("Node: Could not duplicate: " + String(get_class()) + "."); - } - } - - List<PropertyInfo> plist; - - get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { continue; } - String name = E->get().name; - Variant value = get(name).duplicate(true); - - node->set(name, value); + Variant v = p_node->get(E->get().name); + if (v.is_ref()) { + RES res = v; + if (res.is_valid()) { + if (p_resource_remap.has(res)) { + p_node->set(E->get().name, p_resource_remap[res]); + remap_nested_resources(res, p_resource_remap); + } + } + } } - List<GroupInfo> groups; - get_groups(&groups); - - for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) { - node->add_to_group(E->get().name, E->get().persistent); + for (int i = 0; i < p_node->get_child_count(); i++) { + remap_node_resources(p_node->get_child(i), p_resource_remap); } +} - node->set_name(get_name()); - p_new_parent->add_child(node); - - Node *owner = get_owner(); +void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const { + List<PropertyInfo> props; + p_resource->get_property_list(&props); - if (p_reown_map.has(owner)) { - owner = p_reown_map[owner]; - } + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { + continue; + } - if (owner) { - NodePath p = get_path_to(owner); - if (owner != this) { - Node *new_owner = node->get_node(p); - if (new_owner) { - node->set_owner(new_owner); + Variant v = p_resource->get(E->get().name); + if (v.is_ref()) { + RES res = v; + if (res.is_valid()) { + if (p_resource_remap.has(res)) { + p_resource->set(E->get().name, p_resource_remap[res]); + remap_nested_resources(res, p_resource_remap); + } } } } - - for (int i = 0; i < get_child_count(); i++) { - get_child(i)->_duplicate_and_reown(node, p_reown_map); - } } +#endif // Duplication of signals must happen after all the node descendants have been copied, // because re-targeting of connections from some descendant to another is not possible @@ -2245,7 +2271,7 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { List<const Node *> process_list; process_list.push_back(this); - while (!process_list.empty()) { + while (!process_list.is_empty()) { const Node *n = process_list.front()->get(); process_list.pop_front(); @@ -2289,49 +2315,6 @@ void Node::_duplicate_signals(const Node *p_original, Node *p_copy) const { } } -Node *Node::duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const { - ERR_FAIL_COND_V(get_filename() != "", nullptr); - - Object *obj = ClassDB::instance(get_class()); - ERR_FAIL_COND_V_MSG(!obj, nullptr, "Node: Could not duplicate: " + String(get_class()) + "."); - - Node *node = Object::cast_to<Node>(obj); - if (!node) { - memdelete(obj); - ERR_FAIL_V_MSG(nullptr, "Node: Could not duplicate: " + String(get_class()) + "."); - } - node->set_name(get_name()); - - List<PropertyInfo> plist; - - get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - String name = E->get().name; - node->set(name, get(name)); - } - - List<GroupInfo> groups; - get_groups(&groups); - - for (List<GroupInfo>::Element *E = groups.front(); E; E = E->next()) { - node->add_to_group(E->get().name, E->get().persistent); - } - - for (int i = 0; i < get_child_count(); i++) { - get_child(i)->_duplicate_and_reown(node, p_reown_map); - } - - // Duplication of signals must happen after all the node descendants have been copied, - // because re-targeting of connections from some descendant to another is not possible - // if the emitter node comes later in tree order than the receiver - _duplicate_signals(this, node); - return node; -} - static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) { if (p_node->get_owner() == p_by) { p_owned->push_back(p_node); @@ -2342,12 +2325,7 @@ static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) { } } -struct _NodeReplaceByPair { - String name; - Variant value; -}; - -void Node::replace_by(Node *p_node, bool p_keep_data) { +void Node::replace_by(Node *p_node, bool p_keep_groups) { ERR_FAIL_NULL(p_node); ERR_FAIL_COND(p_node->data.parent); @@ -2355,21 +2333,7 @@ void Node::replace_by(Node *p_node, bool p_keep_data) { List<Node *> owned_by_owner; Node *owner = (data.owner == this) ? p_node : data.owner; - List<_NodeReplaceByPair> replace_data; - - if (p_keep_data) { - List<PropertyInfo> plist; - get_property_list(&plist); - - for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { - _NodeReplaceByPair rd; - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - rd.name = E->get().name; - rd.value = get(rd.name); - } - + if (p_keep_groups) { List<GroupInfo> groups; get_groups(&groups); @@ -2414,10 +2378,6 @@ void Node::replace_by(Node *p_node, bool p_keep_data) { } p_node->set_filename(get_filename()); - - for (List<_NodeReplaceByPair>::Element *E = replace_data.front(); E; E = E->next()) { - p_node->set(E->get().name, E->get().value); - } } void Node::_replace_connections_target(Node *p_new_target) { @@ -2709,10 +2669,10 @@ void Node::request_ready() { } void Node::_bind_methods() { - GLOBAL_DEF("node/name_num_separator", 0); - ProjectSettings::get_singleton()->set_custom_property_info("node/name_num_separator", PropertyInfo(Variant::INT, "node/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash")); - GLOBAL_DEF("node/name_casing", NAME_CASING_PASCAL_CASE); - ProjectSettings::get_singleton()->set_custom_property_info("node/name_casing", PropertyInfo(Variant::INT, "node/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case")); + GLOBAL_DEF("editor/node_naming/name_num_separator", 0); + ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_num_separator", PropertyInfo(Variant::INT, "editor/node_naming/name_num_separator", PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash")); + GLOBAL_DEF("editor/node_naming/name_casing", NAME_CASING_PASCAL_CASE); + ProjectSettings::get_singleton()->set_custom_property_info("editor/node_naming/name_casing", PropertyInfo(Variant::INT, "editor/node_naming/name_casing", PROPERTY_HINT_ENUM, "PascalCase,camelCase,snake_case")); ClassDB::bind_method(D_METHOD("add_sibling", "sibling", "legible_unique_name"), &Node::add_sibling, DEFVAL(false)); @@ -2767,8 +2727,8 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("is_processing_unhandled_input"), &Node::is_processing_unhandled_input); ClassDB::bind_method(D_METHOD("set_process_unhandled_key_input", "enable"), &Node::set_process_unhandled_key_input); ClassDB::bind_method(D_METHOD("is_processing_unhandled_key_input"), &Node::is_processing_unhandled_key_input); - ClassDB::bind_method(D_METHOD("set_pause_mode", "mode"), &Node::set_pause_mode); - ClassDB::bind_method(D_METHOD("get_pause_mode"), &Node::get_pause_mode); + ClassDB::bind_method(D_METHOD("set_process_mode", "mode"), &Node::set_process_mode); + ClassDB::bind_method(D_METHOD("get_process_mode"), &Node::get_process_mode); ClassDB::bind_method(D_METHOD("can_process"), &Node::can_process); ClassDB::bind_method(D_METHOD("print_stray_nodes"), &Node::_print_stray_nodes); @@ -2784,7 +2744,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("get_tree"), &Node::get_tree); ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANCING | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); - ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_data"), &Node::replace_by, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); @@ -2806,12 +2766,12 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config); ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config); - ClassDB::bind_method(D_METHOD("_set_editor_description", "editor_description"), &Node::set_editor_description); - ClassDB::bind_method(D_METHOD("_get_editor_description"), &Node::get_editor_description); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_editor_description", "_get_editor_description"); + ClassDB::bind_method(D_METHOD("set_editor_description", "editor_description"), &Node::set_editor_description); + ClassDB::bind_method(D_METHOD("get_editor_description"), &Node::get_editor_description); ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path); ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path"); { @@ -2875,9 +2835,11 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_APPLICATION_FOCUS_OUT); BIND_CONSTANT(NOTIFICATION_TEXT_SERVER_CHANGED); - BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT); - BIND_ENUM_CONSTANT(PAUSE_MODE_STOP); - BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS); + BIND_ENUM_CONSTANT(PROCESS_MODE_INHERIT); + BIND_ENUM_CONSTANT(PROCESS_MODE_PAUSABLE); + BIND_ENUM_CONSTANT(PROCESS_MODE_WHEN_PAUSED); + BIND_ENUM_CONSTANT(PROCESS_MODE_ALWAYS); + BIND_ENUM_CONSTANT(PROCESS_MODE_DISABLED); BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); @@ -2890,15 +2852,19 @@ void Node::_bind_methods() { ADD_SIGNAL(MethodInfo("tree_exiting")); ADD_SIGNAL(MethodInfo("tree_exited")); - 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"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer"); + + ADD_GROUP("Process", "process_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Inherit,Pausable,WhenPaused,Always,Disabled"), "set_process_mode", "get_process_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_priority"), "set_process_priority", "get_process_priority"); + ADD_GROUP("Editor Description", "editor_"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "editor_description", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_INTERNAL), "set_editor_description", "get_editor_description"); + BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::FLOAT, "delta"))); BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::FLOAT, "delta"))); BIND_VMETHOD(MethodInfo("_enter_tree")); @@ -2911,7 +2877,7 @@ void Node::_bind_methods() { } String Node::_get_name_num_separator() { - switch (ProjectSettings::get_singleton()->get("node/name_num_separator").operator int()) { + switch (ProjectSettings::get_singleton()->get("editor/node_naming/name_num_separator").operator int()) { case 0: return ""; case 1: diff --git a/scene/main/node.h b/scene/main/node.h index 5c178d401c..b1e51d2aee 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,10 +46,12 @@ class Node : public Object { OBJ_CATEGORY("Nodes"); public: - enum PauseMode { - PAUSE_MODE_INHERIT, - PAUSE_MODE_STOP, - PAUSE_MODE_PROCESS + enum ProcessMode { + PROCESS_MODE_INHERIT, // same as parent node + PROCESS_MODE_PAUSABLE, // process only if not paused + PROCESS_MODE_WHEN_PAUSED, // process only if paused + PROCESS_MODE_ALWAYS, // process always + PROCESS_MODE_DISABLED, // never process }; enum DuplicateFlags { @@ -80,7 +82,7 @@ private: struct NetData { StringName name; - MultiplayerAPI::RPCMode mode; + MultiplayerAPI::RPCMode mode = MultiplayerAPI::RPCMode::RPC_MODE_DISABLED; }; struct Data { @@ -88,8 +90,6 @@ private: Ref<SceneState> instance_state; Ref<SceneState> inherited_state; - HashMap<NodePath, int> editable_instances; - Node *parent = nullptr; Node *owner = nullptr; Vector<Node *> children; @@ -104,6 +104,7 @@ private: #ifdef TOOLS_ENABLED NodePath import_path; // Path used when imported, used by scene editors to keep tracking. #endif + String editor_description; Viewport *viewport = nullptr; @@ -111,8 +112,8 @@ private: List<Node *>::Element *OW = nullptr; // Owned element. List<Node *> owned; - PauseMode pause_mode = PAUSE_MODE_INHERIT; - Node *pause_owner = nullptr; + ProcessMode process_mode = PROCESS_MODE_INHERIT; + Node *process_owner = nullptr; int network_master = 1; // Server by default. Vector<NetData> rpc_methods; @@ -121,11 +122,11 @@ private: // Variables used to properly sort the node when processing, ignored otherwise. // TODO: Should move all the stuff below to bits. bool physics_process = false; - bool idle_process = false; + bool process = false; int process_priority = 0; bool physics_process_internal = false; - bool idle_process_internal = false; + bool process_internal = false; bool input = false; bool unhandled_input = false; @@ -136,6 +137,7 @@ private: bool use_placeholder = false; bool display_folded = false; + bool editable_instance = false; mutable NodePath *path_cache = nullptr; @@ -167,11 +169,10 @@ private: void _propagate_after_exit_tree(); void _propagate_validate_owner(); void _print_stray_nodes(); - void _propagate_pause_owner(Node *p_owner); + void _propagate_process_owner(Node *p_owner, int p_notification); Array _get_node_and_resource(const NodePath &p_path); void _duplicate_signals(const Node *p_original, Node *p_copy) const; - void _duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p_reown_map) const; Node *_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap = nullptr) const; TypedArray<Node> _get_children() const; @@ -185,12 +186,9 @@ private: friend class SceneTree; void _set_tree(SceneTree *p_tree); + void _propagate_pause_notification(bool p_enable); -#ifdef TOOLS_ENABLED - friend class SceneTreeEditor; -#endif - static String invalid_character; - static bool _validate_node_name(String &p_name); + _FORCE_INLINE_ bool _can_process(bool p_paused) const; protected: void _block() { data.blocked++; } @@ -298,7 +296,7 @@ public: struct GroupInfo { StringName name; - bool persistent; + bool persistent = false; }; void get_groups(List<GroupInfo> *p_groups) const; @@ -325,8 +323,7 @@ public: void set_editable_instance(Node *p_node, bool p_editable); bool is_editable_instance(const Node *p_node) const; - void set_editable_instances(const HashMap<NodePath, int> &p_editable_instances); - HashMap<NodePath, int> get_editable_instances() const; + Node *get_deepest_editable_node(Node *p_start_node) const; /* NOTIFICATIONS */ @@ -339,14 +336,14 @@ public: float get_physics_process_delta_time() const; bool is_physics_processing() const; - void set_process(bool p_idle_process); + void set_process(bool p_process); float get_process_delta_time() const; bool is_processing() const; void set_physics_process_internal(bool p_process_internal); bool is_physics_processing_internal() const; - void set_process_internal(bool p_idle_process_internal); + void set_process_internal(bool p_process_internal); bool is_processing_internal() const; void set_process_priority(int p_priority); @@ -362,9 +359,11 @@ public: bool is_processing_unhandled_key_input() const; Node *duplicate(int p_flags = DUPLICATE_GROUPS | DUPLICATE_SIGNALS | DUPLICATE_SCRIPTS) const; - Node *duplicate_and_reown(const Map<Node *, Node *> &p_reown_map) const; #ifdef TOOLS_ENABLED Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap) const; + Node *duplicate_from_editor(Map<const Node *, Node *> &r_duplimap, const Map<RES, RES> &p_resource_remap) const; + void remap_node_resources(Node *p_node, const Map<RES, RES> &p_resource_remap) const; + void remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resource_remap) const; #endif // used by editors, to save what has changed only @@ -381,8 +380,8 @@ public: void replace_by(Node *p_node, bool p_keep_data = false); - void set_pause_mode(PauseMode p_mode); - PauseMode get_pause_mode() const; + void set_process_mode(ProcessMode p_mode); + ProcessMode get_process_mode() const; bool can_process() const; bool can_process_notification(int p_what) const; diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp index c1d4435687..cd9560db61 100644 --- a/scene/main/resource_preloader.cpp +++ b/scene/main/resource_preloader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h index 580dc35a57..1b7ea3fb9f 100644 --- a/scene/main/resource_preloader.h +++ b/scene/main/resource_preloader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 5cf3cbd382..66f3a2ebde 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -54,6 +54,7 @@ #include "window.h" #include <stdio.h> +#include <stdlib.h> void SceneTreeTimer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left); @@ -72,12 +73,12 @@ float SceneTreeTimer::get_time_left() const { return time_left; } -void SceneTreeTimer::set_pause_mode_process(bool p_pause_mode_process) { - process_pause = p_pause_mode_process; +void SceneTreeTimer::set_process_always(bool p_process_always) { + process_always = p_process_always; } -bool SceneTreeTimer::is_pause_mode_process() { - return process_pause; +bool SceneTreeTimer::is_process_always() { + return process_always; } void SceneTreeTimer::release_connections() { @@ -90,10 +91,7 @@ void SceneTreeTimer::release_connections() { } } -SceneTreeTimer::SceneTreeTimer() { - time_left = 0; - process_pause = true; -} +SceneTreeTimer::SceneTreeTimer() {} void SceneTree::tree_changed() { tree_version++; @@ -136,7 +134,7 @@ void SceneTree::remove_from_group(const StringName &p_group, Node *p_node) { ERR_FAIL_COND(!E); E->get().nodes.erase(p_node); - if (E->get().nodes.empty()) { + if (E->get().nodes.is_empty()) { group_map.erase(E); } } @@ -183,7 +181,7 @@ void SceneTree::_update_group_order(Group &g, bool p_use_priority) { if (!g.changed) { return; } - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -206,7 +204,7 @@ void SceneTree::call_group_flags(uint32_t p_call_flags, const StringName &p_grou return; } Group &g = E->get(); - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -282,7 +280,7 @@ void SceneTree::notify_group_flags(uint32_t p_call_flags, const StringName &p_gr return; } Group &g = E->get(); - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -333,7 +331,7 @@ void SceneTree::set_group_flags(uint32_t p_call_flags, const StringName &p_group return; } Group &g = E->get(); - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -390,25 +388,27 @@ void SceneTree::set_group(const StringName &p_group, const String &p_name, const set_group_flags(0, p_group, p_name, p_value); } -void SceneTree::init() { +void SceneTree::initialize() { + ERR_FAIL_COND(!root); initialized = true; root->_set_tree(this); - MainLoop::init(); + MainLoop::initialize(); } -bool SceneTree::iteration(float p_time) { +bool SceneTree::physics_process(float p_time) { root_lock++; current_frame++; flush_transform_notifications(); - MainLoop::iteration(p_time); + MainLoop::physics_process(p_time); physics_process_time = p_time; emit_signal("physics_frame"); _notify_group_pause("physics_process_internal", Node::NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + call_group_flags(GROUP_CALL_REALTIME, "_viewports", "_process_picking"); _notify_group_pause("physics_process", Node::NOTIFICATION_PHYSICS_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack @@ -422,29 +422,25 @@ bool SceneTree::iteration(float p_time) { return _quit; } -bool SceneTree::idle(float p_time) { - //print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); - //print_line("node count: "+itos(get_node_count())); - //print_line("TEXTURE RAM: "+itos(RS::get_singleton()->get_render_info(RS::INFO_TEXTURE_MEM_USED))); - +bool SceneTree::process(float p_time) { root_lock++; - MainLoop::idle(p_time); + MainLoop::process(p_time); - idle_process_time = p_time; + process_time = p_time; if (multiplayer_poll) { multiplayer->poll(); } - emit_signal("idle_frame"); + emit_signal("process_frame"); MessageQueue::get_singleton()->flush(); //small little hack flush_transform_notifications(); - _notify_group_pause("idle_process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); - _notify_group_pause("idle_process", Node::NOTIFICATION_PROCESS); + _notify_group_pause("process_internal", Node::NOTIFICATION_INTERNAL_PROCESS); + _notify_group_pause("process", Node::NOTIFICATION_PROCESS); _flush_ugc(); MessageQueue::get_singleton()->flush(); //small little hack @@ -461,7 +457,7 @@ bool SceneTree::idle(float p_time) { for (List<Ref<SceneTreeTimer>>::Element *E = timers.front(); E;) { List<Ref<SceneTreeTimer>>::Element *N = E->next(); - if (pause && !E->get()->is_pause_mode_process()) { + if (paused && !E->get()->is_process_always()) { if (E == L) { break; //break on last, so if new timers were added during list traversal, ignore them. } @@ -490,7 +486,7 @@ bool SceneTree::idle(float p_time) { if (Engine::get_singleton()->is_editor_hint()) { //simple hack to reload fallback environment if it changed from editor - String env_path = ProjectSettings::get_singleton()->get("rendering/environment/default_environment"); + String env_path = ProjectSettings::get_singleton()->get("rendering/environment/defaults/default_environment"); env_path = env_path.strip_edges(); //user may have added a space or two String cpath; Ref<Environment> fallback = get_root()->get_world_3d()->get_fallback_environment(); @@ -502,7 +498,7 @@ bool SceneTree::idle(float p_time) { fallback = ResourceLoader::load(env_path); if (fallback.is_null()) { //could not load fallback, set as empty - ProjectSettings::get_singleton()->set("rendering/environment/default_environment", ""); + ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", ""); } } else { fallback.unref(); @@ -516,14 +512,14 @@ bool SceneTree::idle(float p_time) { return _quit; } -void SceneTree::finish() { +void SceneTree::finalize() { _flush_delete_queue(); _flush_ugc(); initialized = false; - MainLoop::finish(); + MainLoop::finalize(); if (root) { root->_set_tree(nullptr); @@ -540,12 +536,7 @@ void SceneTree::finish() { } void SceneTree::quit(int p_exit_code) { - if (p_exit_code >= 0) { - // Override the exit code if a positive argument is given (the default is `-1`). - // This is a shorthand for calling `set_exit_code()` on the OS singleton then quitting. - OS::get_singleton()->set_exit_code(p_exit_code); - } - + OS::get_singleton()->set_exit_code(p_exit_code); _quit = true; } @@ -765,20 +756,20 @@ Ref<ArrayMesh> SceneTree::get_debug_contact_mesh() { } void SceneTree::set_pause(bool p_enabled) { - if (p_enabled == pause) { + if (p_enabled == paused) { return; } - pause = p_enabled; + paused = p_enabled; NavigationServer3D::get_singleton()->set_active(!p_enabled); PhysicsServer3D::get_singleton()->set_active(!p_enabled); PhysicsServer2D::get_singleton()->set_active(!p_enabled); if (get_root()) { - get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED); + get_root()->_propagate_pause_notification(p_enabled); } } bool SceneTree::is_paused() const { - return pause; + return paused; } void SceneTree::_notify_group_pause(const StringName &p_group, int p_notification) { @@ -787,7 +778,7 @@ void SceneTree::_notify_group_pause(const StringName &p_group, int p_notificatio return; } Group &g = E->get(); - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -840,7 +831,7 @@ void SceneTree::_call_input_pause(const StringName &p_group, const StringName &p return; } Group &g = E->get(); - if (g.nodes.empty()) { + if (g.nodes.is_empty()) { return; } @@ -962,6 +953,21 @@ bool SceneTree::has_group(const StringName &p_identifier) const { return group_map.has(p_identifier); } +Node *SceneTree::get_first_node_in_group(const StringName &p_group) { + Map<StringName, Group>::Element *E = group_map.find(p_group); + if (!E) { + return nullptr; //no group + } + + _update_group_order(E->get()); //update order just in case + + if (E->get().nodes.size() == 0) { + return nullptr; + } + + return E->get().nodes[0]; +} + void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_list) { Map<StringName, Group>::Element *E = group_map.find(p_group); if (!E) { @@ -1076,10 +1082,10 @@ void SceneTree::add_current_scene(Node *p_current) { root->add_child(p_current); } -Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) { +Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_always) { Ref<SceneTreeTimer> stt; stt.instance(); - stt->set_pause_mode_process(p_process_pause); + stt->set_process_always(p_process_always); stt->set_time_left(p_delay_sec); timers.push_back(stt); return stt; @@ -1192,11 +1198,11 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause); ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused); - ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "pause_mode_process"), &SceneTree::create_timer, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("create_timer", "time_sec", "process_always"), &SceneTree::create_timer, DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_node_count"), &SceneTree::get_node_count); ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); - ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(EXIT_SUCCESS)); ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); @@ -1222,6 +1228,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("set_group", "group", "property", "value"), &SceneTree::set_group); ClassDB::bind_method(D_METHOD("get_nodes_in_group", "group"), &SceneTree::_get_nodes_in_group); + ClassDB::bind_method(D_METHOD("get_first_node_in_group", "group"), &SceneTree::get_first_node_in_group); ClassDB::bind_method(D_METHOD("set_current_scene", "child_node"), &SceneTree::set_current_scene); ClassDB::bind_method(D_METHOD("get_current_scene"), &SceneTree::get_current_scene); @@ -1260,12 +1267,13 @@ void SceneTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled"); ADD_SIGNAL(MethodInfo("tree_changed")); + ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it cant be removed in run-time ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_renamed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); ADD_SIGNAL(MethodInfo("node_configuration_warning_changed", PropertyInfo(Variant::OBJECT, "node", PROPERTY_HINT_RESOURCE_TYPE, "Node"))); - ADD_SIGNAL(MethodInfo("idle_frame")); + ADD_SIGNAL(MethodInfo("process_frame")); ADD_SIGNAL(MethodInfo("physics_frame")); ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::PACKED_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen"))); @@ -1303,7 +1311,7 @@ void SceneTree::get_argument_options(const StringName &p_function, int p_idx, Li List<String> directories; directories.push_back(dir_access->get_current_dir()); - while (!directories.empty()) { + while (!directories.is_empty()) { dir_access->change_dir(directories.back()->get()); directories.pop_back(); @@ -1332,13 +1340,15 @@ SceneTree::SceneTree() { if (singleton == nullptr) { singleton = this; } - debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.5)); + debug_collisions_color = GLOBAL_DEF("debug/shapes/collision/shape_color", Color(0.0, 0.6, 0.7, 0.42)); debug_collision_contact_color = GLOBAL_DEF("debug/shapes/collision/contact_color", Color(1.0, 0.2, 0.1, 0.8)); debug_navigation_color = GLOBAL_DEF("debug/shapes/navigation/geometry_color", Color(0.1, 1.0, 0.7, 0.4)); debug_navigation_disabled_color = GLOBAL_DEF("debug/shapes/navigation/disabled_geometry_color", Color(1.0, 0.7, 0.1, 0.4)); collision_debug_contacts = GLOBAL_DEF("debug/shapes/collision/max_contacts_displayed", 10000); ProjectSettings::get_singleton()->set_custom_property_info("debug/shapes/collision/max_contacts_displayed", PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1")); // No negative + GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true); + // Create with mainloop. root = memnew(Window); @@ -1355,34 +1365,54 @@ SceneTree::SceneTree() { root->set_as_audio_listener_2d(true); current_scene = nullptr; - 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)")); + const int msaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/msaa", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/msaa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/msaa", PROPERTY_HINT_ENUM, "Disabled (Fastest),2x (Fast),4x (Average),8x (Slow),16x (Slower)")); root->set_msaa(Viewport::MSAA(msaa_mode)); - 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)")); + const int ssaa_mode = GLOBAL_DEF("rendering/anti_aliasing/quality/screen_space_aa", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/quality/screen_space_aa", PropertyInfo(Variant::INT, "rendering/anti_aliasing/quality/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); + const bool use_debanding = GLOBAL_DEF("rendering/anti_aliasing/quality/use_debanding", false); root->set_use_debanding(use_debanding); - float lod_threshold = GLOBAL_DEF("rendering/quality/mesh_lod/threshold_pixels", 1.0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/mesh_lod/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/quality/mesh_lod/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1")); + float lod_threshold = GLOBAL_DEF("rendering/mesh_lod/lod_change/threshold_pixels", 1.0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/mesh_lod/lod_change/threshold_pixels", PropertyInfo(Variant::FLOAT, "rendering/mesh_lod/lod_change/threshold_pixels", PROPERTY_HINT_RANGE, "0,1024,0.1")); root->set_lod_threshold(lod_threshold); - bool snap_2d_transforms = GLOBAL_DEF("rendering/quality/2d/snap_2d_transforms_to_pixel", false); + bool snap_2d_transforms = GLOBAL_DEF("rendering/2d/snap/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); + bool snap_2d_vertices = GLOBAL_DEF("rendering/2d/snap/snap_2d_vertices_to_pixel", false); root->set_snap_2d_vertices_to_pixel(snap_2d_vertices); - Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/quality/2d_sdf/oversize", 1))); + int shadowmap_size = GLOBAL_DEF("rendering/shadows/shadow_atlas/size", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/size", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/size", PROPERTY_HINT_RANGE, "256,16384")); + GLOBAL_DEF("rendering/shadows/shadow_atlas/size.mobile", 2048); + bool shadowmap_16_bits = GLOBAL_DEF("rendering/shadows/shadow_atlas/16_bits", true); + int atlas_q0 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_0_subdiv", 2); + int atlas_q1 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_1_subdiv", 2); + int atlas_q2 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_2_subdiv", 3); + int atlas_q3 = GLOBAL_DEF("rendering/shadows/shadow_atlas/quadrant_3_subdiv", 4); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_0_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_0_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_1_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_1_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_2_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_2_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadow_atlas/quadrant_3_subdiv", PropertyInfo(Variant::INT, "rendering/shadows/shadow_atlas/quadrant_3_subdiv", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows")); + + root->set_shadow_atlas_size(shadowmap_size); + root->set_shadow_atlas_16_bits(shadowmap_16_bits); + root->set_shadow_atlas_quadrant_subdiv(0, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q0)); + root->set_shadow_atlas_quadrant_subdiv(1, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q1)); + root->set_shadow_atlas_quadrant_subdiv(2, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q2)); + root->set_shadow_atlas_quadrant_subdiv(3, Viewport::ShadowAtlasQuadrantSubdiv(atlas_q3)); + + Viewport::SDFOversize sdf_oversize = Viewport::SDFOversize(int(GLOBAL_DEF("rendering/2d/sdf/oversize", 1))); root->set_sdf_oversize(sdf_oversize); - Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/quality/2d_sdf/scale", 1))); + Viewport::SDFScale sdf_scale = Viewport::SDFScale(int(GLOBAL_DEF("rendering/2d/sdf/scale", 1))); root->set_sdf_scale(sdf_scale); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/oversize", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%")); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/2d_sdf/scale", PropertyInfo(Variant::INT, "rendering/quality/2d_sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/oversize", PropertyInfo(Variant::INT, "rendering/2d/sdf/oversize", PROPERTY_HINT_ENUM, "100%,120%,150%,200%")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/sdf/scale", PropertyInfo(Variant::INT, "rendering/2d/sdf/scale", PROPERTY_HINT_ENUM, "100%,50%,25%")); { // Load default fallback environment. // Get possible extensions. @@ -1396,9 +1426,9 @@ SceneTree::SceneTree() { ext_hint += "*." + E->get(); } // Get path. - String env_path = GLOBAL_DEF("rendering/environment/default_environment", ""); + String env_path = GLOBAL_DEF("rendering/environment/defaults/default_environment", ""); // Setup property. - ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/defaults/default_environment", PropertyInfo(Variant::STRING, "rendering/viewport/default_environment", PROPERTY_HINT_FILE, ext_hint)); env_path = env_path.strip_edges(); if (env_path != String()) { Ref<Environment> env = ResourceLoader::load(env_path); @@ -1407,7 +1437,7 @@ SceneTree::SceneTree() { } else { if (Engine::get_singleton()->is_editor_hint()) { // File was erased, clear the field. - ProjectSettings::get_singleton()->set("rendering/environment/default_environment", ""); + ProjectSettings::get_singleton()->set("rendering/environment/defaults/default_environment", ""); } else { // File was erased, notify user. ERR_PRINT(RTR("Default Environment as specified in Project Settings (Rendering -> Environment -> Default Environment) could not be loaded.")); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 9cf129d959..a2f2adb8f8 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,8 +51,8 @@ class SceneDebugger; class SceneTreeTimer : public Reference { GDCLASS(SceneTreeTimer, Reference); - float time_left; - bool process_pause; + float time_left = 0.0; + bool process_always = true; protected: static void _bind_methods(); @@ -61,8 +61,8 @@ public: void set_time_left(float p_time); float get_time_left() const; - void set_pause_mode_process(bool p_pause_mode_process); - bool is_pause_mode_process(); + void set_process_always(bool p_process_always); + bool is_process_always(); void release_connections(); @@ -80,15 +80,14 @@ public: private: struct Group { Vector<Node *> nodes; - bool changed; - Group() { changed = false; }; + bool changed = false; }; Window *root = nullptr; uint64_t tree_version = 1; float physics_process_time = 1.0; - float idle_process_time = 1.0; + float process_time = 1.0; bool accept_quit = true; bool quit_on_go_back = true; @@ -96,7 +95,7 @@ private: bool debug_collisions_hint = false; bool debug_navigation_hint = false; #endif - bool pause = false; + bool paused = false; int root_lock = 0; Map<StringName, Group> group_map; @@ -236,20 +235,20 @@ public: void flush_transform_notifications(); - virtual void init() override; + virtual void initialize() override; - virtual bool iteration(float p_time) override; - virtual bool idle(float p_time) override; + virtual bool physics_process(float p_time) override; + virtual bool process(float p_time) override; - virtual void finish() override; + virtual void finalize() override; void set_auto_accept_quit(bool p_enable); void set_quit_on_go_back(bool p_enable); - void quit(int p_exit_code = -1); + void quit(int p_exit_code = EXIT_SUCCESS); _FORCE_INLINE_ float get_physics_process_time() const { return physics_process_time; } - _FORCE_INLINE_ float get_idle_process_time() const { return idle_process_time; } + _FORCE_INLINE_ float get_process_time() const { return process_time; } #ifdef TOOLS_ENABLED bool is_node_being_edited(const Node *p_node) const; @@ -303,6 +302,7 @@ public: void queue_delete(Object *p_object); void get_nodes_in_group(const StringName &p_group, List<Node *> *p_list); + Node *get_first_node_in_group(const StringName &p_group); bool has_group(const StringName &p_identifier) const; //void change_scene(const String& p_path); @@ -317,7 +317,7 @@ public: Error change_scene_to(const Ref<PackedScene> &p_scene); Error reload_current_scene(); - Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_pause = true); + Ref<SceneTreeTimer> create_timer(float p_delay_sec, bool p_process_always = true); //used by Main::start, don't use otherwise void add_current_scene(Node *p_current); diff --git a/scene/main/shader_globals_override.cpp b/scene/main/shader_globals_override.cpp index 432fb5b4fb..b6b2982155 100644 --- a/scene/main/shader_globals_override.cpp +++ b/scene/main/shader_globals_override.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -264,7 +264,7 @@ String ShaderGlobalsOverride::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!active) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("ShaderGlobalsOverride is not active because another node of the same type is in the scene."); @@ -277,6 +277,4 @@ void ShaderGlobalsOverride::_bind_methods() { ClassDB::bind_method(D_METHOD("_activate"), &ShaderGlobalsOverride::_activate); } -ShaderGlobalsOverride::ShaderGlobalsOverride() { - active = false; -} +ShaderGlobalsOverride::ShaderGlobalsOverride() {} diff --git a/scene/main/shader_globals_override.h b/scene/main/shader_globals_override.h index fea1677ad7..8d8794d465 100644 --- a/scene/main/shader_globals_override.h +++ b/scene/main/shader_globals_override.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,7 +43,7 @@ class ShaderGlobalsOverride : public Node { StringName *_remap(const StringName &p_name) const; - bool active; + bool active = false; mutable HashMap<StringName, Override> overrides; mutable HashMap<StringName, StringName> param_remaps; diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 1c6037d26e..4bc159f6aa 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,7 +46,7 @@ void Timer::_notification(int p_what) { } } break; case NOTIFICATION_INTERNAL_PROCESS: { - if (!processing || timer_process_mode == TIMER_PROCESS_PHYSICS || !is_processing_internal()) { + if (!processing || timer_process_callback == TIMER_PROCESS_PHYSICS || !is_processing_internal()) { return; } time_left -= get_process_delta_time(); @@ -63,7 +63,7 @@ void Timer::_notification(int p_what) { } break; case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - if (!processing || timer_process_mode == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) { + if (!processing || timer_process_callback == TIMER_PROCESS_IDLE || !is_physics_processing_internal()) { return; } time_left -= get_physics_process_delta_time(); @@ -143,12 +143,12 @@ float Timer::get_time_left() const { return time_left > 0 ? time_left : 0; } -void Timer::set_timer_process_mode(TimerProcessMode p_mode) { - if (timer_process_mode == p_mode) { +void Timer::set_timer_process_callback(TimerProcessCallback p_callback) { + if (timer_process_callback == p_callback) { return; } - switch (timer_process_mode) { + switch (timer_process_callback) { case TIMER_PROCESS_PHYSICS: if (is_physics_processing_internal()) { set_physics_process_internal(false); @@ -162,15 +162,15 @@ void Timer::set_timer_process_mode(TimerProcessMode p_mode) { } break; } - timer_process_mode = p_mode; + timer_process_callback = p_callback; } -Timer::TimerProcessMode Timer::get_timer_process_mode() const { - return timer_process_mode; +Timer::TimerProcessCallback Timer::get_timer_process_callback() const { + return timer_process_callback; } void Timer::_set_process(bool p_process, bool p_force) { - switch (timer_process_mode) { + switch (timer_process_callback) { case TIMER_PROCESS_PHYSICS: set_physics_process_internal(p_process && !paused); break; @@ -201,12 +201,12 @@ void Timer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_time_left"), &Timer::get_time_left); - ClassDB::bind_method(D_METHOD("set_timer_process_mode", "mode"), &Timer::set_timer_process_mode); - ClassDB::bind_method(D_METHOD("get_timer_process_mode"), &Timer::get_timer_process_mode); + ClassDB::bind_method(D_METHOD("set_timer_process_callback", "callback"), &Timer::set_timer_process_callback); + ClassDB::bind_method(D_METHOD("get_timer_process_callback"), &Timer::get_timer_process_callback); ADD_SIGNAL(MethodInfo("timeout")); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_mode", "get_timer_process_mode"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "process_callback", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_timer_process_callback", "get_timer_process_callback"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.001,4096,0.001,or_greater"), "set_wait_time", "get_wait_time"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart"); @@ -217,12 +217,4 @@ void Timer::_bind_methods() { BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE); } -Timer::Timer() { - timer_process_mode = TIMER_PROCESS_IDLE; - autostart = false; - wait_time = 1; - one_shot = false; - time_left = -1; - processing = false; - paused = false; -} +Timer::Timer() {} diff --git a/scene/main/timer.h b/scene/main/timer.h index 61abf04f59..3d9e21d7fc 100644 --- a/scene/main/timer.h +++ b/scene/main/timer.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,20 +36,20 @@ class Timer : public Node { GDCLASS(Timer, Node); - float wait_time; - bool one_shot; - bool autostart; - bool processing; - bool paused; + float wait_time = 1.0; + bool one_shot = false; + bool autostart = false; + bool processing = false; + bool paused = false; - double time_left; + double time_left = -1.0; protected: void _notification(int p_what); static void _bind_methods(); public: - enum TimerProcessMode { + enum TimerProcessCallback { TIMER_PROCESS_PHYSICS, TIMER_PROCESS_IDLE, }; @@ -73,15 +73,15 @@ public: float get_time_left() const; - void set_timer_process_mode(TimerProcessMode p_mode); - TimerProcessMode get_timer_process_mode() const; + void set_timer_process_callback(TimerProcessCallback p_callback); + TimerProcessCallback get_timer_process_callback() const; Timer(); private: - TimerProcessMode timer_process_mode; + TimerProcessCallback timer_process_callback = TIMER_PROCESS_IDLE; void _set_process(bool p_process, bool p_force = false); }; -VARIANT_ENUM_CAST(Timer::TimerProcessMode); +VARIANT_ENUM_CAST(Timer::TimerProcessCallback); #endif // TIMER_H diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index c96dd4ad35..5df35d1e6a 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -131,7 +131,7 @@ bool ViewportTexture::has_alpha() const { return false; } -Ref<Image> ViewportTexture::get_data() const { +Ref<Image> ViewportTexture::get_image() const { ERR_FAIL_COND_V_MSG(!vp, Ref<Image>(), "Viewport Texture must be set to use it."); return RS::get_singleton()->texture_2d_get(vp->texture_rid); } @@ -144,7 +144,6 @@ void ViewportTexture::_bind_methods() { } ViewportTexture::ViewportTexture() { - vp = nullptr; set_local_to_scene(true); } @@ -184,26 +183,6 @@ public: ///////////////////////////////////// -Viewport::GUI::GUI() { - embed_subwindows_hint = false; - embedding_subwindows = false; - - dragging = false; - mouse_focus = nullptr; - forced_mouse_focus = false; - mouse_click_grabber = nullptr; - mouse_focus_mask = 0; - key_focus = nullptr; - mouse_over = nullptr; - drag_mouse_over = nullptr; - - tooltip_control = nullptr; - tooltip_popup = nullptr; - tooltip_label = nullptr; -} - -///////////////////////////////////// - void Viewport::update_worlds() { if (!is_inside_tree()) { return; @@ -299,6 +278,11 @@ void Viewport::_sub_window_update(Window *p_window) { int x = (r.size.width - title_text.get_size().x) / 2; int y = (-title_height - title_text.get_size().y) / 2; + Color font_outline_color = p_window->get_theme_color("title_outline_modulate"); + int outline_size = p_window->get_theme_constant("title_outline_size"); + if (outline_size > 0 && font_outline_color.a > 0) { + title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color); + } title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color); bool hl = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside; @@ -468,7 +452,7 @@ void Viewport::_notification(int p_what) { //3D PhysicsServer3D::get_singleton()->space_set_debug_contacts(find_world_3d()->get_space(), get_tree()->get_collision_debug_contact_count()); contact_3d_debug_multimesh = RenderingServer::get_singleton()->multimesh_create(); - RenderingServer::get_singleton()->multimesh_allocate(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true); + RenderingServer::get_singleton()->multimesh_allocate_data(contact_3d_debug_multimesh, get_tree()->get_collision_debug_contact_count(), RS::MULTIMESH_TRANSFORM_3D, true); RenderingServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, 0); RenderingServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh, get_tree()->get_debug_contact_mesh()->get_rid()); contact_3d_debug_instance = RenderingServer::get_singleton()->instance_create(); @@ -567,280 +551,297 @@ void Viewport::_notification(int p_what) { int point_count = PhysicsServer3D::get_singleton()->space_get_contact_count(find_world_3d()->get_space()); RS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh, point_count); + + for (int i = 0; i < point_count; i++) { + Transform point_transform; + point_transform.origin = points[i]; + RS::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh, i, point_transform); + } + } + } break; + 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(); + + if (gui.mouse_focus && !gui.forced_mouse_focus) { + _drop_mouse_focus(); } + } break; + } +} + +void Viewport::_process_picking() { + if (!is_inside_tree()) { + return; + } + if (!physics_object_picking) { + return; + } + if (to_screen_rect != Rect2i() && Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) { + return; + } + + _drop_physics_mouseover(true); - if (physics_object_picking && (to_screen_rect == Rect2i() || Input::get_singleton()->get_mouse_mode() != Input::MOUSE_MODE_CAPTURED)) { #ifndef _3D_DISABLED - Vector2 last_pos(1e20, 1e20); - CollisionObject3D *last_object = nullptr; - ObjectID last_id; + Vector2 last_pos(1e20, 1e20); + CollisionObject3D *last_object = nullptr; + ObjectID last_id; #endif - PhysicsDirectSpaceState3D::RayResult result; - PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); - - if (physics_has_last_mousepos) { - // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. - // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame - bool has_mouse_event = false; - for (List<Ref<InputEvent>>::Element *E = physics_picking_events.front(); E; E = E->next()) { - Ref<InputEventMouse> m = E->get(); - if (m.is_valid()) { - has_mouse_event = true; - break; - } - } + PhysicsDirectSpaceState3D::RayResult result; + PhysicsDirectSpaceState2D *ss2d = PhysicsServer2D::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); + + if (physics_has_last_mousepos) { + // if no mouse event exists, create a motion one. This is necessary because objects or camera may have moved. + // while this extra event is sent, it is checked if both camera and last object and last ID did not move. If nothing changed, the event is discarded to avoid flooding with unnecessary motion events every frame + bool has_mouse_event = false; + for (List<Ref<InputEvent>>::Element *E = physics_picking_events.front(); E; E = E->next()) { + Ref<InputEventMouse> m = E->get(); + if (m.is_valid()) { + has_mouse_event = true; + break; + } + } - if (!has_mouse_event) { - Ref<InputEventMouseMotion> mm; - mm.instance(); - - mm->set_device(InputEvent::DEVICE_ID_INTERNAL); - mm->set_global_position(physics_last_mousepos); - mm->set_position(physics_last_mousepos); - mm->set_alt(physics_last_mouse_state.alt); - mm->set_shift(physics_last_mouse_state.shift); - mm->set_control(physics_last_mouse_state.control); - mm->set_metakey(physics_last_mouse_state.meta); - mm->set_button_mask(physics_last_mouse_state.mouse_mask); - physics_picking_events.push_back(mm); - } - } + if (!has_mouse_event) { + Ref<InputEventMouseMotion> mm; + mm.instance(); - while (physics_picking_events.size()) { - Ref<InputEvent> ev = physics_picking_events.front()->get(); - physics_picking_events.pop_front(); + mm->set_device(InputEvent::DEVICE_ID_INTERNAL); + mm->set_global_position(physics_last_mousepos); + mm->set_position(physics_last_mousepos); + mm->set_alt(physics_last_mouse_state.alt); + mm->set_shift(physics_last_mouse_state.shift); + mm->set_control(physics_last_mouse_state.control); + mm->set_metakey(physics_last_mouse_state.meta); + mm->set_button_mask(physics_last_mouse_state.mouse_mask); + physics_picking_events.push_back(mm); + } + } - Vector2 pos; - bool is_mouse = false; + while (physics_picking_events.size()) { + Ref<InputEvent> ev = physics_picking_events.front()->get(); + physics_picking_events.pop_front(); - Ref<InputEventMouseMotion> mm = ev; + Vector2 pos; + bool is_mouse = false; - if (mm.is_valid()) { - pos = mm->get_position(); - is_mouse = true; + Ref<InputEventMouseMotion> mm = ev; - physics_has_last_mousepos = true; - physics_last_mousepos = pos; - physics_last_mouse_state.alt = mm->get_alt(); - physics_last_mouse_state.shift = mm->get_shift(); - physics_last_mouse_state.control = mm->get_control(); - physics_last_mouse_state.meta = mm->get_metakey(); - physics_last_mouse_state.mouse_mask = mm->get_button_mask(); - } + if (mm.is_valid()) { + pos = mm->get_position(); + is_mouse = true; - Ref<InputEventMouseButton> mb = ev; + physics_has_last_mousepos = true; + physics_last_mousepos = pos; + physics_last_mouse_state.alt = mm->get_alt(); + physics_last_mouse_state.shift = mm->get_shift(); + physics_last_mouse_state.control = mm->get_control(); + physics_last_mouse_state.meta = mm->get_metakey(); + physics_last_mouse_state.mouse_mask = mm->get_button_mask(); + } - if (mb.is_valid()) { - pos = mb->get_position(); - is_mouse = true; + Ref<InputEventMouseButton> mb = ev; - physics_has_last_mousepos = true; - physics_last_mousepos = pos; - physics_last_mouse_state.alt = mb->get_alt(); - physics_last_mouse_state.shift = mb->get_shift(); - physics_last_mouse_state.control = mb->get_control(); - physics_last_mouse_state.meta = mb->get_metakey(); + if (mb.is_valid()) { + pos = mb->get_position(); + is_mouse = true; - if (mb->is_pressed()) { - physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1)); - } else { - physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1)); + physics_has_last_mousepos = true; + physics_last_mousepos = pos; + physics_last_mouse_state.alt = mb->get_alt(); + physics_last_mouse_state.shift = mb->get_shift(); + physics_last_mouse_state.control = mb->get_control(); + physics_last_mouse_state.meta = mb->get_metakey(); - // If touch mouse raised, assume we don't know last mouse pos until new events come - if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { - physics_has_last_mousepos = false; - } - } - } + if (mb->is_pressed()) { + physics_last_mouse_state.mouse_mask |= (1 << (mb->get_button_index() - 1)); + } else { + physics_last_mouse_state.mouse_mask &= ~(1 << (mb->get_button_index() - 1)); - Ref<InputEventKey> k = ev; - if (k.is_valid()) { - //only for mask - physics_last_mouse_state.alt = k->get_alt(); - physics_last_mouse_state.shift = k->get_shift(); - physics_last_mouse_state.control = k->get_control(); - physics_last_mouse_state.meta = k->get_metakey(); - continue; - } + // If touch mouse raised, assume we don't know last mouse pos until new events come + if (mb->get_device() == InputEvent::DEVICE_ID_TOUCH_MOUSE) { + physics_has_last_mousepos = false; + } + } + } - Ref<InputEventScreenDrag> sd = ev; + Ref<InputEventKey> k = ev; + if (k.is_valid()) { + //only for mask + physics_last_mouse_state.alt = k->get_alt(); + physics_last_mouse_state.shift = k->get_shift(); + physics_last_mouse_state.control = k->get_control(); + physics_last_mouse_state.meta = k->get_metakey(); + continue; + } - if (sd.is_valid()) { - pos = sd->get_position(); - } + Ref<InputEventScreenDrag> sd = ev; - Ref<InputEventScreenTouch> st = ev; + if (sd.is_valid()) { + pos = sd->get_position(); + } - if (st.is_valid()) { - pos = st->get_position(); - } + Ref<InputEventScreenTouch> st = ev; - if (ss2d) { - //send to 2D + if (st.is_valid()) { + pos = st->get_position(); + } - uint64_t frame = get_tree()->get_frame(); + if (ss2d) { + //send to 2D - PhysicsDirectSpaceState2D::ShapeResult res[64]; - for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) { - Transform2D canvas_transform; - ObjectID canvas_layer_id; - if (E->get()) { - // A descendant CanvasLayer - canvas_transform = E->get()->get_transform(); - canvas_layer_id = E->get()->get_instance_id(); - } else { - // This Viewport's builtin canvas - canvas_transform = get_canvas_transform(); - canvas_layer_id = ObjectID(); - } + uint64_t frame = get_tree()->get_frame(); + + PhysicsDirectSpaceState2D::ShapeResult res[64]; + for (Set<CanvasLayer *>::Element *E = canvas_layers.front(); E; E = E->next()) { + Transform2D canvas_transform; + ObjectID canvas_layer_id; + if (E->get()) { + // A descendant CanvasLayer + canvas_transform = E->get()->get_transform(); + canvas_layer_id = E->get()->get_instance_id(); + } else { + // This Viewport's builtin canvas + canvas_transform = get_canvas_transform(); + canvas_layer_id = ObjectID(); + } - Vector2 point = canvas_transform.affine_inverse().xform(pos); - - int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true); - for (int i = 0; i < rc; i++) { - if (res[i].collider_id.is_valid() && res[i].collider) { - CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); - if (co) { - bool send_event = true; - if (is_mouse) { - Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); - - if (!F) { - physics_2d_mouseover.insert(res[i].collider_id, frame); - co->_mouse_enter(); - } else { - F->get() = frame; - // It was already hovered, so don't send the event if it's faked - if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { - send_event = false; - } - } - } - - if (send_event) { - co->_input_event(this, ev, res[i].shape); - } + Vector2 point = canvas_transform.affine_inverse().xform(pos); + + int rc = ss2d->intersect_point_on_canvas(point, canvas_layer_id, res, 64, Set<RID>(), 0xFFFFFFFF, true, true, true); + for (int i = 0; i < rc; i++) { + if (res[i].collider_id.is_valid() && res[i].collider) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); + if (co && co->can_process()) { + bool send_event = true; + if (is_mouse) { + Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); + + if (!F) { + physics_2d_mouseover.insert(res[i].collider_id, frame); + co->_mouse_enter(); + } else { + F->get() = frame; + // It was already hovered, so don't send the event if it's faked + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { + send_event = false; } } } - } - if (is_mouse) { - List<Map<ObjectID, uint64_t>::Element *> to_erase; - - for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { - if (E->get() != frame) { - Object *o = ObjectDB::get_instance(E->key()); - if (o) { - CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); - if (co) { - co->_mouse_exit(); - } - } - to_erase.push_back(E); - } + if (send_event) { + co->_input_event(this, ev, res[i].shape); } + } + } + } + } + + if (is_mouse) { + List<Map<ObjectID, uint64_t>::Element *> to_erase; - while (to_erase.size()) { - physics_2d_mouseover.erase(to_erase.front()->get()); - to_erase.pop_front(); + for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { + if (E->get() != frame) { + Object *o = ObjectDB::get_instance(E->key()); + if (o) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + if (co) { + co->_mouse_exit(); } } + to_erase.push_back(E); } + } + + while (to_erase.size()) { + physics_2d_mouseover.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + } + } #ifndef _3D_DISABLED - bool captured = false; - - if (physics_object_capture.is_valid()) { - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture)); - if (co && camera) { - _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); - captured = true; - if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { - physics_object_capture = ObjectID(); - } + bool captured = false; + + if (physics_object_capture.is_valid()) { + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_capture)); + if (co && camera) { + _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0); + captured = true; + if (mb.is_valid() && mb->get_button_index() == 1 && !mb->is_pressed()) { + physics_object_capture = ObjectID(); + } - } else { - physics_object_capture = ObjectID(); + } else { + physics_object_capture = ObjectID(); + } + } + + if (captured) { + //none + } else if (pos == last_pos) { + if (last_id.is_valid()) { + if (ObjectDB::get_instance(last_id) && last_object) { + //good, exists + _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape); + if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { + physics_object_capture = last_id; + } + } + } + } else { + if (camera) { + Vector3 from = camera->project_ray_origin(pos); + Vector3 dir = camera->project_ray_normal(pos); + + PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world_3d()->get_space()); + if (space) { + bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true); + ObjectID new_collider; + if (col) { + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider); + if (co && co->can_process()) { + _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape); + last_object = co; + last_id = result.collider_id; + new_collider = last_id; + if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { + physics_object_capture = last_id; + } } } - if (captured) { - //none - } else if (pos == last_pos) { - if (last_id.is_valid()) { - if (ObjectDB::get_instance(last_id) && last_object) { - //good, exists - _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape); - if (last_object->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { - physics_object_capture = last_id; - } + if (is_mouse && new_collider != physics_object_over) { + if (physics_object_over.is_valid()) { + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over)); + if (co) { + co->_mouse_exit(); } } - } else { - if (camera) { - Vector3 from = camera->project_ray_origin(pos); - Vector3 dir = camera->project_ray_normal(pos); - - PhysicsDirectSpaceState3D *space = PhysicsServer3D::get_singleton()->space_get_direct_state(find_world_3d()->get_space()); - if (space) { - bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true); - ObjectID new_collider; - if (col) { - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(result.collider); - if (co) { - _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape); - last_object = co; - last_id = result.collider_id; - new_collider = last_id; - if (co->get_capture_input_on_drag() && mb.is_valid() && mb->get_button_index() == 1 && mb->is_pressed()) { - physics_object_capture = last_id; - } - } - } - if (is_mouse && new_collider != physics_object_over) { - if (physics_object_over.is_valid()) { - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over)); - if (co) { - co->_mouse_exit(); - } - } - - if (new_collider.is_valid()) { - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider)); - if (co) { - co->_mouse_enter(); - } - } - - physics_object_over = new_collider; - } + if (new_collider.is_valid()) { + CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(new_collider)); + if (co) { + co->_mouse_enter(); } - - last_pos = pos; } + + physics_object_over = new_collider; } -#endif } - } - - } break; - 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(); - if (gui.mouse_focus && !gui.forced_mouse_focus) { - _drop_mouse_focus(); + last_pos = pos; } - } break; + } +#endif } } @@ -1162,7 +1163,7 @@ void Viewport::set_world_2d(const Ref<World2D> &p_world_2d) { if (p_world_2d.is_valid()) { world_2d = p_world_2d; } else { - WARN_PRINT("Invalid world_3d"); + WARN_PRINT("Invalid world_2d"); world_2d = Ref<World2D>(memnew(World2D)); } @@ -1416,18 +1417,26 @@ Ref<ViewportTexture> Viewport::get_texture() const { } void Viewport::set_shadow_atlas_size(int p_size) { - if (shadow_atlas_size == p_size) { - return; - } - shadow_atlas_size = p_size; - RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size); + RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, p_size, shadow_atlas_16_bits); } int Viewport::get_shadow_atlas_size() const { return shadow_atlas_size; } +void Viewport::set_shadow_atlas_16_bits(bool p_16_bits) { + if (shadow_atlas_16_bits == p_16_bits) { + return; + } + + shadow_atlas_16_bits = p_16_bits; + RS::get_singleton()->viewport_set_shadow_atlas_size(viewport, shadow_atlas_size, shadow_atlas_16_bits); +} + +bool Viewport::get_shadow_atlas_16_bits() const { + return shadow_atlas_16_bits; +} void Viewport::set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv) { ERR_FAIL_INDEX(p_quadrant, 4); ERR_FAIL_INDEX(p_subdiv, SHADOW_ATLAS_QUADRANT_SUBDIV_MAX); @@ -1505,7 +1514,7 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont } // If we found a tooltip, we stop here. - if (!tooltip.empty()) { + if (!tooltip.is_empty()) { break; } @@ -1538,8 +1547,8 @@ void Viewport::_gui_show_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()) { + tooltip_text = tooltip_text.strip_edges(); + if (tooltip_text.is_empty()) { return; // Nothing to show. } @@ -1565,7 +1574,7 @@ void Viewport::_gui_show_tooltip() { base_tooltip = gui.tooltip_label; } - base_tooltip->set_anchors_and_margins_preset(Control::PRESET_WIDE); + base_tooltip->set_anchors_and_offsets_preset(Control::PRESET_WIDE); TooltipPanel *panel = memnew(TooltipPanel); panel->set_transient(false); @@ -1580,7 +1589,8 @@ void Viewport::_gui_show_tooltip() { 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()); - Rect2i vr = gui.tooltip_popup->get_parent_visible_window()->get_usable_parent_rect(); + Window *window = gui.tooltip_popup->get_parent_visible_window(); + Rect2i vr = window->get_usable_parent_rect(); if (r.size.x + r.position.x > vr.size.x + vr.position.x) { r.position.x = vr.position.x + vr.size.x - r.size.x; @@ -1594,6 +1604,7 @@ void Viewport::_gui_show_tooltip() { r.position.y = vr.position.y; } + gui.tooltip_popup->set_current_screen(window->get_current_screen()); gui.tooltip_popup->set_position(r.position); gui.tooltip_popup->set_size(r.size); @@ -1610,10 +1621,10 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu Ref<InputEventMouseButton> mb = p_input; bool cant_stop_me_now = (mb.is_valid() && - (mb->get_button_index() == BUTTON_WHEEL_DOWN || - mb->get_button_index() == BUTTON_WHEEL_UP || - mb->get_button_index() == BUTTON_WHEEL_LEFT || - mb->get_button_index() == BUTTON_WHEEL_RIGHT)); + (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN || + mb->get_button_index() == MOUSE_BUTTON_WHEEL_UP || + mb->get_button_index() == MOUSE_BUTTON_WHEEL_LEFT || + mb->get_button_index() == MOUSE_BUTTON_WHEEL_RIGHT)); Ref<InputEventPanGesture> pn = p_input; cant_stop_me_now = pn.is_valid() || cant_stop_me_now; @@ -1759,19 +1770,22 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_ } } - if (!c) { + if (!c || c->data.mouse_filter == Control::MOUSE_FILTER_IGNORE) { return nullptr; } matrix.affine_invert(); + if (!c->has_point(matrix.xform(p_global))) { + return nullptr; + } - //conditions for considering this as a valid control for return - if (c->data.mouse_filter != Control::MOUSE_FILTER_IGNORE && c->has_point(matrix.xform(p_global)) && (!gui.drag_preview || (c != gui.drag_preview && !gui.drag_preview->is_a_parent_of(c)))) { + Control *drag_preview = _gui_get_drag_preview(); + if (!drag_preview || (c != drag_preview && !drag_preview->is_a_parent_of(c))) { r_inv_xform = matrix; return c; - } else { - return nullptr; } + + return nullptr; } bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_check) { @@ -1846,7 +1860,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1); - if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { gui.drag_accum = Vector2(); gui.drag_attempted = false; } @@ -1869,7 +1883,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } #endif - if (mb->get_button_index() == BUTTON_LEFT) { //assign focus + if (mb->get_button_index() == MOUSE_BUTTON_LEFT) { //assign focus CanvasItem *ci = gui.mouse_focus; while (ci) { Control *control = Object::cast_to<Control>(ci); @@ -1900,7 +1914,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { set_input_as_handled(); - if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { + if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) { //alternate drop use (when using force_drag(), as proposed by #5342 if (gui.mouse_focus) { _gui_drop(gui.mouse_focus, pos, false); @@ -1909,9 +1923,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.drag_data = Variant(); gui.dragging = false; - if (gui.drag_preview) { - memdelete(gui.drag_preview); - gui.drag_preview = nullptr; + Control *drag_preview = _gui_get_drag_preview(); + if (drag_preview) { + memdelete(drag_preview); + gui.drag_preview_id = ObjectID(); } _propagate_viewport_notification(this, NOTIFICATION_DRAG_END); //change mouse accordingly @@ -1919,14 +1934,15 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_cancel_tooltip(); } else { - if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) { + if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (gui.drag_mouse_over) { _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, false); } - if (gui.drag_preview && mb->get_button_index() == BUTTON_LEFT) { - memdelete(gui.drag_preview); - gui.drag_preview = nullptr; + Control *drag_preview = _gui_get_drag_preview(); + if (drag_preview) { + memdelete(drag_preview); + gui.drag_preview_id = ObjectID(); } gui.drag_data = Variant(); @@ -1962,7 +1978,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _gui_call_input(mouse_focus, mb); } - /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) { + /*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==MOUSE_BUTTON_LEFT) { _propagate_viewport_notification(this,NOTIFICATION_DRAG_END); gui.drag_data=Variant(); //always clear }*/ @@ -2006,7 +2022,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Control *over = nullptr; // D&D - if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & BUTTON_MASK_LEFT) { + if (!gui.drag_attempted && gui.mouse_focus && mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { gui.drag_accum += mm->get_relative(); float len = gui.drag_accum.length(); if (len > 10) { @@ -2023,10 +2039,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { gui.mouse_focus_mask = 0; break; } else { - if (gui.drag_preview != nullptr) { + Control *drag_preview = _gui_get_drag_preview(); + if (drag_preview) { ERR_PRINT("Don't set a drag preview and return null data. Preview was deleted and drag request ignored."); - memdelete(gui.drag_preview); - gui.drag_preview = nullptr; + memdelete(drag_preview); + gui.drag_preview_id = ObjectID(); } gui.dragging = false; } @@ -2166,8 +2183,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (gui.drag_data.get_type() != Variant::NIL) { //handle dragandrop - if (gui.drag_preview) { - gui.drag_preview->set_position(mpos); + Control *drag_preview = _gui_get_drag_preview(); + if (drag_preview) { + drag_preview->set_position(mpos); } gui.drag_mouse_over = over; @@ -2183,7 +2201,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { embedder = this; viewport_pos = mpos; } else { - //not an embeder, but may be a subwindow of an embedder + //not an embedder, but may be a subwindow of an embedder Window *w = Object::cast_to<Window>(this); if (w) { if (w->is_embedded()) { @@ -2248,7 +2266,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { Transform2D localizer = gui.drag_mouse_over->get_global_transform_with_canvas().affine_inverse(); gui.drag_mouse_over_pos = localizer.xform(viewport_pos); - if (mm->get_button_mask() & BUTTON_MASK_LEFT) { + if (mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT) { bool can_drop = _gui_drop(gui.drag_mouse_over, gui.drag_mouse_over_pos, true); if (!can_drop) { @@ -2375,7 +2393,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { //keyboard focus //if (from && p_event->is_pressed() && !p_event->get_alt() && !p_event->get_metakey() && !p_event->key->get_command()) { Ref<InputEventKey> k = p_event; - //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/righ/etc> is handled here when it shouldn't be. + //need to check for mods, otherwise any combination of alt/ctrl/shift+<up/down/left/right/etc> is handled here when it shouldn't be. bool mods = k.is_valid() && (k->get_control() || k->get_alt() || k->get_shift() || k->get_metakey()); if (from && p_event->is_pressed()) { @@ -2392,19 +2410,19 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { } if (!mods && p_event->is_action_pressed("ui_up") && input->is_action_just_pressed("ui_up")) { - next = from->_get_focus_neighbor(MARGIN_TOP); + next = from->_get_focus_neighbor(SIDE_TOP); } if (!mods && p_event->is_action_pressed("ui_left") && input->is_action_just_pressed("ui_left")) { - next = from->_get_focus_neighbor(MARGIN_LEFT); + next = from->_get_focus_neighbor(SIDE_LEFT); } if (!mods && p_event->is_action_pressed("ui_right") && input->is_action_just_pressed("ui_right")) { - next = from->_get_focus_neighbor(MARGIN_RIGHT); + next = from->_get_focus_neighbor(SIDE_RIGHT); } if (!mods && p_event->is_action_pressed("ui_down") && input->is_action_just_pressed("ui_down")) { - next = from->_get_focus_neighbor(MARGIN_BOTTOM); + next = from->_get_focus_neighbor(SIDE_BOTTOM); } if (next) { @@ -2442,15 +2460,29 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) { ERR_FAIL_COND(p_control->is_inside_tree()); ERR_FAIL_COND(p_control->get_parent() != nullptr); - if (gui.drag_preview) { - memdelete(gui.drag_preview); + Control *drag_preview = _gui_get_drag_preview(); + if (drag_preview) { + memdelete(drag_preview); } 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(); - gui.drag_preview = p_control; + gui.drag_preview_id = p_control->get_instance_id(); +} + +Control *Viewport::_gui_get_drag_preview() { + if (gui.drag_preview_id.is_null()) { + return nullptr; + } else { + Control *drag_preview = Object::cast_to<Control>(ObjectDB::get_instance(gui.drag_preview_id)); + if (!drag_preview) { + ERR_PRINT("Don't free the control set as drag preview."); + gui.drag_preview_id = ObjectID(); + } + return drag_preview; + } } void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) { @@ -2572,28 +2604,41 @@ void Viewport::_drop_mouse_focus() { } } -void Viewport::_drop_physics_mouseover() { +void Viewport::_drop_physics_mouseover(bool p_paused_only) { physics_has_last_mousepos = false; - while (physics_2d_mouseover.size()) { - Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key()); + List<Map<ObjectID, uint64_t>::Element *> to_erase; + + for (Map<ObjectID, uint64_t>::Element *E = physics_2d_mouseover.front(); E; E = E->next()) { + Object *o = ObjectDB::get_instance(E->key()); if (o) { CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); - co->_mouse_exit(); + if (co) { + if (p_paused_only && co->can_process()) { + continue; + } + co->_mouse_exit(); + to_erase.push_back(E); + } } - physics_2d_mouseover.erase(physics_2d_mouseover.front()); + } + + while (to_erase.size()) { + physics_2d_mouseover.erase(to_erase.front()->get()); + to_erase.pop_front(); } #ifndef _3D_DISABLED if (physics_object_over.is_valid()) { CollisionObject3D *co = Object::cast_to<CollisionObject3D>(ObjectDB::get_instance(physics_object_over)); if (co) { - co->_mouse_exit(); + if (!(p_paused_only && co->can_process())) { + co->_mouse_exit(); + physics_object_over = ObjectID(); + physics_object_capture = ObjectID(); + } } } - - physics_object_over = ObjectID(); - physics_object_capture = ObjectID(); #endif } @@ -2627,7 +2672,7 @@ void Viewport::_post_gui_grab_click_focus() { Ref<InputEventMouseButton> mb; mb.instance(); - //send unclic + //send unclick mb->set_position(click); mb->set_button_index(i + 1); @@ -2645,7 +2690,7 @@ void Viewport::_post_gui_grab_click_focus() { Ref<InputEventMouseButton> mb; mb.instance(); - //send clic + //send click mb->set_position(click); mb->set_button_index(i + 1); @@ -2738,7 +2783,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND_V(gui.subwindow_focused == nullptr, false); Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { if (gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE) { if (gui.subwindow_drag_close_rect.has_point(mb->get_position())) { //close window @@ -2863,7 +2908,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; //if the event is a mouse button, we need to check whether another window was clicked - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) { bool click_on_window = false; for (int i = gui.sub_windows.size() - 1; i >= 0; i--) { SubWindow &sw = gui.sub_windows.write[i]; @@ -3139,7 +3184,7 @@ String Viewport::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (size.x == 0 || size.y == 0) { - if (!warning.empty()) { + if (!warning.is_empty()) { warning += "\n\n"; } warning += TTR("Viewport size must be greater than 0 to render anything."); @@ -3479,6 +3524,9 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shadow_atlas_size", "size"), &Viewport::set_shadow_atlas_size); ClassDB::bind_method(D_METHOD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size); + ClassDB::bind_method(D_METHOD("set_shadow_atlas_16_bits", "enable"), &Viewport::set_shadow_atlas_16_bits); + ClassDB::bind_method(D_METHOD("get_shadow_atlas_16_bits"), &Viewport::get_shadow_atlas_16_bits); + 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); @@ -3516,6 +3564,8 @@ void Viewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_lod_threshold", "pixels"), &Viewport::set_lod_threshold); ClassDB::bind_method(D_METHOD("get_lod_threshold"), &Viewport::get_lod_threshold); + ClassDB::bind_method(D_METHOD("_process_picking"), &Viewport::_process_picking); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world_3d"), "set_use_own_world_3d", "is_using_own_world_3d"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_3d", PROPERTY_HINT_RESOURCE_TYPE, "World3D"), "set_world_3d", "get_world_3d"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d"); @@ -3546,6 +3596,7 @@ void Viewport::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "sdf_scale", PROPERTY_HINT_ENUM, "100%,50%,25%"), "set_sdf_scale", "get_sdf_scale"); ADD_GROUP("Shadow Atlas", "shadow_atlas_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "shadow_atlas_size"), "set_shadow_atlas_size", "get_shadow_atlas_size"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shadow_atlas_16_bits"), "set_shadow_atlas_16_bits", "get_shadow_atlas_16_bits"); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_0", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 0); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1); ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2); @@ -3603,6 +3654,10 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(DEBUG_DRAW_SDFGI_PROBES); BIND_ENUM_CONSTANT(DEBUG_DRAW_GI_BUFFER); BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLE_LOD); + BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_OMNI_LIGHTS); + BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_SPOT_LIGHTS); + BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_DECALS); + BIND_ENUM_CONSTANT(DEBUG_DRAW_CLUSTER_REFLECTION_PROBES); BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST); BIND_ENUM_CONSTANT(DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR); @@ -3638,25 +3693,12 @@ Viewport::Viewport() { viewport_textures.insert(default_texture.ptr()); default_texture->proxy = RS::get_singleton()->texture_proxy_create(texture_rid); - audio_listener = false; //internal_listener_2d = SpatialSound2DServer::get_singleton()->listener_create(); - audio_listener_2d = false; - transparent_bg = false; - parent = nullptr; - listener = nullptr; - camera = nullptr; - override_canvas_transform = false; canvas_layers.insert(nullptr); // This eases picking code (interpreted as the canvas of the Viewport) - gen_mipmaps = false; - //clear=true; + set_shadow_atlas_size(shadow_atlas_size); - physics_object_picking = false; - physics_has_last_mousepos = false; - physics_last_mousepos = Vector2(Math_INF, Math_INF); - - shadow_atlas_size = 0; for (int i = 0; i < 4; i++) { shadow_atlas_quadrant_subdiv[i] = SHADOW_ATLAS_QUADRANT_SUBDIV_MAX; } @@ -3673,50 +3715,11 @@ Viewport::Viewport() { unhandled_input_group = "_vp_unhandled_input" + id; unhandled_key_input_group = "_vp_unhandled_key_input" + id; - disable_input = false; - // Window tooltip. - gui.tooltip_timer = -1; - 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_control = nullptr; - gui.tooltip_label = nullptr; - gui.drag_preview = nullptr; - gui.drag_attempted = false; - gui.canvas_sort_index = 0; - gui.roots_order_dirty = false; - gui.mouse_focus = nullptr; - gui.forced_mouse_focus = false; - gui.last_mouse_focus = nullptr; - gui.subwindow_focused = nullptr; - gui.subwindow_drag = SUB_WINDOW_DRAG_DISABLED; - - msaa = MSAA_DISABLED; - screen_space_aa = SCREEN_SPACE_AA_DISABLED; - 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; - physics_last_mouse_state.meta = false; - physics_last_mouse_state.mouse_mask = 0; - local_input_handled = false; - handle_input_locally = true; - - size_allocated = false; - - default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR; - default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - - sdf_oversize = SDF_OVERSIZE_120_PERCENT; - sdf_scale = SDF_SCALE_50_PERCENT; - set_sdf_oversize(SDF_OVERSIZE_120_PERCENT); //set to server + set_sdf_oversize(sdf_oversize); //set to server } Viewport::~Viewport() { @@ -3848,12 +3851,6 @@ void SubViewport::_bind_methods() { BIND_ENUM_CONSTANT(UPDATE_ALWAYS); } -SubViewport::SubViewport() { - xr = false; - size_2d_override_stretch = false; - update_mode = UPDATE_WHEN_VISIBLE; - clear_mode = CLEAR_MODE_ALWAYS; -} +SubViewport::SubViewport() {} -SubViewport::~SubViewport() { -} +SubViewport::~SubViewport() {} diff --git a/scene/main/viewport.h b/scene/main/viewport.h index ffbc3c782a..8e79b50385 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -56,7 +56,7 @@ class ViewportTexture : public Texture2D { NodePath path; friend class Viewport; - Viewport *vp; + Viewport *vp = nullptr; mutable RID proxy_ph; mutable RID proxy; @@ -77,7 +77,7 @@ public: virtual bool has_alpha() const override; - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; ViewportTexture(); ~ViewportTexture(); @@ -143,6 +143,10 @@ public: DEBUG_DRAW_SDFGI_PROBES, DEBUG_DRAW_GI_BUFFER, DEBUG_DRAW_DISABLE_LOD, + DEBUG_DRAW_CLUSTER_OMNI_LIGHTS, + DEBUG_DRAW_CLUSTER_SPOT_LIGHTS, + DEBUG_DRAW_CLUSTER_DECALS, + DEBUG_DRAW_CLUSTER_REFLECTION_PROBES, }; enum DefaultCanvasItemTextureFilter { @@ -182,9 +186,9 @@ public: private: friend class ViewportTexture; - Viewport *parent; + Viewport *parent = nullptr; - Listener3D *listener; + Listener3D *listener = nullptr; Set<Listener3D *> listeners; struct CameraOverrideData { @@ -193,11 +197,11 @@ private: PROJECTION_PERSPECTIVE, PROJECTION_ORTHOGONAL }; - Projection projection; - float fov; - float size; - float z_near; - float z_far; + Projection projection = Projection::PROJECTION_PERSPECTIVE; + float fov = 0.0; + float size = 0.0; + float z_near = 0.0; + float z_far = 0.0; RID rid; operator bool() const { @@ -205,7 +209,7 @@ private: } } camera_override; - Camera3D *camera; + Camera3D *camera = nullptr; Set<Camera3D *> cameras; Set<CanvasLayer *> canvas_layers; @@ -213,13 +217,13 @@ private: RID current_canvas; RID subwindow_canvas; - bool audio_listener; + bool audio_listener = false; RID internal_listener; - bool audio_listener_2d; + bool audio_listener_2d = false; RID internal_listener_2d; - bool override_canvas_transform; + bool override_canvas_transform = false; Transform2D canvas_transform_override; Transform2D canvas_transform; @@ -228,7 +232,7 @@ private: Size2i size; Size2i size_2d_override; - bool size_allocated; + bool size_allocated = false; RID contact_2d_debug; RID contact_3d_debug_multimesh; @@ -236,36 +240,36 @@ private: Rect2 last_vp_rect; - bool transparent_bg; + bool transparent_bg = false; bool filter; - bool gen_mipmaps; + bool gen_mipmaps = false; - bool snap_controls_to_pixels; - bool snap_2d_transforms_to_pixel; - bool snap_2d_vertices_to_pixel; + bool snap_controls_to_pixels = true; + bool snap_2d_transforms_to_pixel = false; + bool snap_2d_vertices_to_pixel = false; - bool physics_object_picking; + bool physics_object_picking = false; List<Ref<InputEvent>> physics_picking_events; ObjectID physics_object_capture; ObjectID physics_object_over; Transform physics_last_object_transform; Transform physics_last_camera_transform; ObjectID physics_last_id; - bool physics_has_last_mousepos; - Vector2 physics_last_mousepos; + bool physics_has_last_mousepos = false; + Vector2 physics_last_mousepos = Vector2(Math_INF, Math_INF); struct { - bool alt; - bool control; - bool shift; - bool meta; - int mouse_mask; + bool alt = false; + bool control = false; + bool shift = false; + bool meta = false; + int mouse_mask = 0; } physics_last_mouse_state; void _collision_object_input_event(CollisionObject3D *p_object, Camera3D *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape); - bool handle_input_locally; - bool local_input_handled; + bool handle_input_locally = true; + bool local_input_handled = false; Map<ObjectID, uint64_t> physics_2d_mouseover; @@ -290,21 +294,22 @@ private: RID texture_rid; - DebugDraw debug_draw; + DebugDraw debug_draw = DEBUG_DRAW_DISABLED; - int shadow_atlas_size; + int shadow_atlas_size = 2048; + bool shadow_atlas_16_bits = true; ShadowAtlasQuadrantSubdiv shadow_atlas_quadrant_subdiv[4]; - MSAA msaa; - ScreenSpaceAA screen_space_aa; + MSAA msaa = MSAA_DISABLED; + ScreenSpaceAA screen_space_aa = SCREEN_SPACE_AA_DISABLED; bool use_debanding = false; float lod_threshold = 1.0; Ref<ViewportTexture> default_texture; Set<ViewportTexture *> viewport_textures; - SDFOversize sdf_oversize; - SDFScale sdf_scale; + SDFOversize sdf_oversize = SDF_OVERSIZE_120_PERCENT; + SDFScale sdf_scale = SDF_SCALE_50_PERCENT; enum SubWindowDrag { SUB_WINDOW_DRAG_DISABLED, @@ -327,60 +332,58 @@ private: }; struct SubWindow { - Window *window; + Window *window = nullptr; RID canvas_item; }; struct GUI { // info used when this is a window - bool forced_mouse_focus; //used for menu buttons - bool key_event_accepted; - Control *mouse_focus; - Control *last_mouse_focus; - Control *mouse_click_grabber; - int mouse_focus_mask; - Control *key_focus; - Control *mouse_over; - Control *drag_mouse_over; + bool forced_mouse_focus = false; //used for menu buttons + bool key_event_accepted = false; + Control *mouse_focus = nullptr; + Control *last_mouse_focus = nullptr; + Control *mouse_click_grabber = nullptr; + int mouse_focus_mask = 0; + Control *key_focus = nullptr; + Control *mouse_over = nullptr; + Control *drag_mouse_over = nullptr; Vector2 drag_mouse_over_pos; - Control *tooltip_control; - Window *tooltip_popup; - Label *tooltip_label; + Control *tooltip_control = nullptr; + Window *tooltip_popup = nullptr; + Label *tooltip_label = nullptr; Point2 tooltip_pos; Point2 last_mouse_pos; Point2 drag_accum; - bool drag_attempted; + bool drag_attempted = false; Variant drag_data; - Control *drag_preview; - float tooltip_timer; - float tooltip_delay; + ObjectID drag_preview_id; + float tooltip_timer = -1.0; + float tooltip_delay = 0.0; Transform2D focus_inv_xform; - bool roots_order_dirty; + bool roots_order_dirty = false; List<Control *> roots; - int canvas_sort_index; //for sorting items with canvas as root - bool dragging; - bool embed_subwindows_hint; - bool embedding_subwindows; + int canvas_sort_index = 0; //for sorting items with canvas as root + bool dragging = false; + bool embed_subwindows_hint = false; + bool embedding_subwindows = false; - Window *subwindow_focused; - SubWindowDrag subwindow_drag; + Window *subwindow_focused = nullptr; + SubWindowDrag subwindow_drag = SUB_WINDOW_DRAG_DISABLED; Vector2 subwindow_drag_from; Vector2 subwindow_drag_pos; Rect2i subwindow_drag_close_rect; - bool subwindow_drag_close_inside; + bool subwindow_drag_close_inside = false; SubWindowResize subwindow_resize_mode; Rect2i subwindow_resize_from_rect; Vector<SubWindow> sub_windows; - - GUI(); } gui; - DefaultCanvasItemTextureFilter default_canvas_item_texture_filter; - DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat; + DefaultCanvasItemTextureFilter default_canvas_item_texture_filter = DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR; + DefaultCanvasItemTextureRepeat default_canvas_item_texture_repeat = DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - bool disable_input; + bool disable_input = false; void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input); void _gui_call_notification(Control *p_control, int p_what); @@ -412,6 +415,7 @@ private: 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); + Control *_gui_get_drag_preview(); void _gui_remove_focus_for_window(Node *p_window); void _gui_remove_focus(); @@ -445,7 +449,7 @@ private: void _canvas_layer_remove(CanvasLayer *p_canvas_layer); void _drop_mouse_focus(); - void _drop_physics_mouseover(); + void _drop_physics_mouseover(bool p_paused_only = false); void _update_canvas_items(Node *p_node); @@ -474,6 +478,7 @@ protected: bool _is_size_allocated() const; void _notification(int p_what); + void _process_picking(); static void _bind_methods(); virtual void _validate_property(PropertyInfo &property) const override; @@ -533,6 +538,9 @@ public: void set_shadow_atlas_size(int p_size); int get_shadow_atlas_size() const; + void set_shadow_atlas_16_bits(bool p_16_bits); + bool get_shadow_atlas_16_bits() const; + void set_shadow_atlas_quadrant_subdiv(int p_quadrant, ShadowAtlasQuadrantSubdiv p_subdiv); ShadowAtlasQuadrantSubdiv get_shadow_atlas_quadrant_subdiv(int p_quadrant) const; @@ -642,10 +650,10 @@ public: }; private: - UpdateMode update_mode; - ClearMode clear_mode; - bool xr; - bool size_2d_override_stretch; + UpdateMode update_mode = UPDATE_WHEN_VISIBLE; + ClearMode clear_mode = CLEAR_MODE_ALWAYS; + bool xr = false; + bool size_2d_override_stretch = false; protected: static void _bind_methods(); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index ad87139332..bacb0030bb 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -232,7 +232,7 @@ void Window::_make_window() { DisplayServer::get_singleton()->window_set_current_screen(current_screen, window_id); DisplayServer::get_singleton()->window_set_max_size(max_size, window_id); DisplayServer::get_singleton()->window_set_min_size(min_size, window_id); - DisplayServer::get_singleton()->window_set_title(title, window_id); + DisplayServer::get_singleton()->window_set_title(tr(title), window_id); DisplayServer::get_singleton()->window_attach_instance_id(get_instance_id(), window_id); _update_window_size(); @@ -759,6 +759,10 @@ void Window::_notification(int p_what) { } } + if (p_what == NOTIFICATION_TRANSLATION_CHANGED) { + child_controls_changed(); + } + if (p_what == NOTIFICATION_EXIT_TREE) { if (transient) { _clear_transient(); @@ -826,6 +830,9 @@ bool Window::is_using_font_oversampling() const { } DisplayServer::WindowID Window::get_window_id() const { + if (embedder) { + return parent->get_window_id(); + } return window_id; } @@ -881,10 +888,6 @@ bool Window::_can_consume_input_events() const { } void Window::_window_input(const Ref<InputEvent> &p_ev) { - if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_ev.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_ev))) { - return; //avoid joy input on editor - } - if (EngineDebugger::is_active()) { //quit from game window using F8 Ref<InputEventKey> k = p_ev; @@ -894,12 +897,13 @@ 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 = focus_target->exclusive_child; focus_target->grab_focus(); - } + }*/ if (!is_embedding_subwindows()) { //not embedding, no need for event return; @@ -1039,6 +1043,9 @@ void Window::popup_centered_ratio(float p_ratio) { void Window::popup(const Rect2i &p_screen_rect) { emit_signal("about_to_popup"); + // Update window size to calculate the actual window size based on contents minimum size and minimum size. + _update_window_size(); + if (p_screen_rect != Rect2i()) { set_position(p_screen_rect.position); set_size(p_screen_rect.size); @@ -1283,14 +1290,14 @@ bool Window::is_layout_rtl() const { if (parent) { return parent->is_layout_rtl(); } else { - if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) { + if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); return TS->is_locale_right_to_left(locale); } } else if (layout_dir == LAYOUT_DIRECTION_LOCALE) { - if (GLOBAL_GET("display/window/force_right_to_left_layout_direction")) { + if (GLOBAL_GET("internationalization/rendering/force_right_to_left_layout_direction")) { return true; } String locale = TranslationServer::get_singleton()->get_tool_locale(); @@ -1349,8 +1356,8 @@ void Window::_bind_methods() { ClassDB::bind_method(D_METHOD("has_focus"), &Window::has_focus); ClassDB::bind_method(D_METHOD("grab_focus"), &Window::grab_focus); - ClassDB::bind_method(D_METHOD("set_ime_active"), &Window::set_ime_active); - ClassDB::bind_method(D_METHOD("set_ime_position"), &Window::set_ime_position); + ClassDB::bind_method(D_METHOD("set_ime_active", "active"), &Window::set_ime_active); + ClassDB::bind_method(D_METHOD("set_ime_position", "position"), &Window::set_ime_position); ClassDB::bind_method(D_METHOD("is_embedded"), &Window::is_embedded); @@ -1466,11 +1473,6 @@ void Window::_bind_methods() { } Window::Window() { - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; - } - content_scale_mode = CONTENT_SCALE_MODE_DISABLED; - content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; RS::get_singleton()->viewport_set_update_mode(get_viewport_rid(), RS::VIEWPORT_UPDATE_DISABLED); } diff --git a/scene/main/window.h b/scene/main/window.h index 20f8309952..38846ed00e 100644 --- a/scene/main/window.h +++ b/scene/main/window.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -90,7 +90,7 @@ private: mutable Size2i min_size; mutable Size2i max_size; mutable Mode mode = MODE_WINDOWED; - mutable bool flags[FLAG_MAX]; + mutable bool flags[FLAG_MAX] = {}; bool visible = true; bool focused = false; @@ -106,8 +106,8 @@ private: void _update_child_controls(); Size2i content_scale_size; - ContentScaleMode content_scale_mode; - ContentScaleAspect content_scale_aspect; + ContentScaleMode content_scale_mode = CONTENT_SCALE_MODE_DISABLED; + ContentScaleAspect content_scale_aspect = CONTENT_SCALE_ASPECT_IGNORE; void _make_window(); void _clear_window(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 30077aa642..93964db8da 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -50,7 +50,6 @@ #include "scene/2d/line_2d.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/multimesh_instance_2d.h" -#include "scene/2d/navigation_2d.h" #include "scene/2d/navigation_agent_2d.h" #include "scene/2d/navigation_obstacle_2d.h" #include "scene/2d/parallax_background.h" @@ -175,6 +174,7 @@ #include "scene/resources/video_stream.h" #include "scene/resources/visual_shader.h" #include "scene/resources/visual_shader_nodes.h" +#include "scene/resources/visual_shader_sdf_nodes.h" #include "scene/resources/world_2d.h" #include "scene/resources/world_3d.h" #include "scene/resources/world_margin_shape_3d.h" @@ -205,7 +205,6 @@ #include "scene/3d/listener_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/multimesh_instance_3d.h" -#include "scene/3d/navigation_3d.h" #include "scene/3d/navigation_agent_3d.h" #include "scene/3d/navigation_obstacle_3d.h" #include "scene/3d/navigation_region_3d.h" @@ -515,7 +514,6 @@ void register_scene_types() { ClassDB::register_class<ConeTwistJoint3D>(); ClassDB::register_class<Generic6DOFJoint3D>(); - ClassDB::register_class<Navigation3D>(); ClassDB::register_class<NavigationRegion3D>(); ClassDB::register_class<NavigationAgent3D>(); ClassDB::register_class<NavigationObstacle3D>(); @@ -533,6 +531,7 @@ void register_scene_types() { ClassDB::register_virtual_class<VisualShaderNodeOutput>(); ClassDB::register_virtual_class<VisualShaderNodeResizableBase>(); ClassDB::register_virtual_class<VisualShaderNodeGroupBase>(); + ClassDB::register_virtual_class<VisualShaderNodeConstant>(); ClassDB::register_class<VisualShaderNodeFloatConstant>(); ClassDB::register_class<VisualShaderNodeIntConstant>(); ClassDB::register_class<VisualShaderNodeBooleanConstant>(); @@ -555,19 +554,14 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeDeterminant>(); ClassDB::register_class<VisualShaderNodeScalarDerivativeFunc>(); ClassDB::register_class<VisualShaderNodeVectorDerivativeFunc>(); - ClassDB::register_class<VisualShaderNodeScalarClamp>(); - ClassDB::register_class<VisualShaderNodeVectorClamp>(); + ClassDB::register_class<VisualShaderNodeClamp>(); ClassDB::register_class<VisualShaderNodeFaceForward>(); ClassDB::register_class<VisualShaderNodeOuterProduct>(); - ClassDB::register_class<VisualShaderNodeVectorScalarStep>(); - ClassDB::register_class<VisualShaderNodeScalarSmoothStep>(); - ClassDB::register_class<VisualShaderNodeVectorSmoothStep>(); - ClassDB::register_class<VisualShaderNodeVectorScalarSmoothStep>(); + ClassDB::register_class<VisualShaderNodeSmoothStep>(); + ClassDB::register_class<VisualShaderNodeStep>(); ClassDB::register_class<VisualShaderNodeVectorDistance>(); ClassDB::register_class<VisualShaderNodeVectorRefract>(); - ClassDB::register_class<VisualShaderNodeScalarInterp>(); - ClassDB::register_class<VisualShaderNodeVectorInterp>(); - ClassDB::register_class<VisualShaderNodeVectorScalarMix>(); + ClassDB::register_class<VisualShaderNodeMix>(); ClassDB::register_class<VisualShaderNodeVectorCompose>(); ClassDB::register_class<VisualShaderNodeTransformCompose>(); ClassDB::register_class<VisualShaderNodeVectorDecompose>(); @@ -593,7 +587,6 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCubemapUniform>(); ClassDB::register_class<VisualShaderNodeIf>(); ClassDB::register_class<VisualShaderNodeSwitch>(); - ClassDB::register_class<VisualShaderNodeScalarSwitch>(); ClassDB::register_class<VisualShaderNodeFresnel>(); ClassDB::register_class<VisualShaderNodeExpression>(); ClassDB::register_class<VisualShaderNodeGlobalExpression>(); @@ -601,6 +594,12 @@ void register_scene_types() { ClassDB::register_class<VisualShaderNodeCompare>(); ClassDB::register_class<VisualShaderNodeMultiplyAdd>(); + ClassDB::register_class<VisualShaderNodeSDFToScreenUV>(); + ClassDB::register_class<VisualShaderNodeScreenUVToSDF>(); + ClassDB::register_class<VisualShaderNodeTextureSDF>(); + ClassDB::register_class<VisualShaderNodeTextureSDFNormal>(); + ClassDB::register_class<VisualShaderNodeSDFRaymarch>(); + ClassDB::register_class<ShaderMaterial>(); ClassDB::register_virtual_class<CanvasItem>(); ClassDB::register_class<CanvasTexture>(); @@ -791,7 +790,6 @@ void register_scene_types() { ClassDB::register_class<PathFollow2D>(); ClassDB::register_class<NavigationMesh>(); - ClassDB::register_class<Navigation2D>(); ClassDB::register_class<NavigationPolygon>(); ClassDB::register_class<NavigationRegion2D>(); ClassDB::register_class<NavigationAgent2D>(); @@ -812,6 +810,8 @@ void register_scene_types() { ClassDB::add_compatibility_class("DynamicFont", "Font"); ClassDB::add_compatibility_class("DynamicFontData", "FontData"); ClassDB::add_compatibility_class("ToolButton", "Button"); + ClassDB::add_compatibility_class("Navigation3D", "Node3D"); + ClassDB::add_compatibility_class("Navigation2D", "Node2D"); // Renamed in 4.0. // Keep alphabetical ordering to easily locate classes and avoid duplicates. @@ -863,7 +863,6 @@ void register_scene_types() { ClassDB::add_compatibility_class("Listener", "Listener3D"); ClassDB::add_compatibility_class("MeshInstance", "MeshInstance3D"); ClassDB::add_compatibility_class("MultiMeshInstance", "MultiMeshInstance3D"); - ClassDB::add_compatibility_class("Navigation", "Navigation3D"); ClassDB::add_compatibility_class("NavigationAgent", "NavigationAgent3D"); ClassDB::add_compatibility_class("NavigationMeshInstance", "NavigationRegion3D"); ClassDB::add_compatibility_class("NavigationObstacle", "NavigationObstacle3D"); @@ -927,6 +926,16 @@ void register_scene_types() { ClassDB::add_compatibility_class("VisualShaderNodeScalarFunc", "VisualShaderNodeFloatFunc"); ClassDB::add_compatibility_class("VisualShaderNodeScalarOp", "VisualShaderNodeFloatOp"); ClassDB::add_compatibility_class("VisualShaderNodeScalarUniform", "VisualShaderNodeFloatUniform"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarClamp", "VisualShaderNodeClamp"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorClamp", "VisualShaderNodeClamp"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarInterp", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorInterp", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarMix", "VisualShaderNodeMix"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarSmoothStep", "VisualShaderNodeSmoothStep"); + ClassDB::add_compatibility_class("VisualShaderNodeVectorScalarStep", "VisualShaderNodeStep"); + ClassDB::add_compatibility_class("VisualShaderNodeScalarSwitch", "VisualShaderNodeSwitch"); ClassDB::add_compatibility_class("World", "World3D"); ClassDB::add_compatibility_class("StreamTexture", "StreamTexture2D"); ClassDB::add_compatibility_class("Light2D", "PointLight2D"); @@ -936,17 +945,19 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init for (int i = 0; i < 20; i++) { - GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), ""); - GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), ""); - GLOBAL_DEF("layer_names/3d_render/layer_" + itos(i + 1), ""); - GLOBAL_DEF("layer_names/3d_physics/layer_" + itos(i + 1), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/2d_render/layer_%d", i), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/2d_physics/layer_%d", i), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/2d_navigation/layer_%d", i), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/3d_render/layer_%d", i), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/3d_physics/layer_%d", i), ""); + GLOBAL_DEF_BASIC(vformat("layer_names/3d_navigation/layer_%d", i), ""); } bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - String theme_path = GLOBAL_DEF("gui/theme/custom", ""); + String theme_path = GLOBAL_DEF_RST("gui/theme/custom", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); - String font_path = GLOBAL_DEF("gui/theme/custom_font", ""); + String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", ""); ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)); Ref<Font> font; diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h index 603321991e..1ff542eef8 100644 --- a/scene/register_scene_types.h +++ b/scene/register_scene_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index f4670ca850..6f64ac6d04 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -580,6 +580,10 @@ void Animation::_get_property_list(List<PropertyInfo> *p_list) const { } } +void Animation::reset_state() { + clear(); +} + int Animation::add_track(TrackType p_type, int p_at_pos) { if (p_at_pos < 0 || p_at_pos >= tracks.size()) { p_at_pos = tracks.size(); @@ -1604,7 +1608,7 @@ T Animation::_interpolate(const Vector<TKey<T>> &p_keys, float p_time, Interpola bool result = true; int next = 0; - float c = 0; + float c = 0.0; // prepare for all cases of interpolation if (loop && p_loop_wrap) { @@ -2278,8 +2282,8 @@ float Animation::bezier_track_interpolate(int p_track, float p_time) const { int iterations = 10; float duration = bt->values[idx + 1].time - bt->values[idx].time; // time duration between our two keyframes - float low = 0; // 0% of the current animation segment - float high = 1; // 100% of the current animation segment + float low = 0.0; // 0% of the current animation segment + float high = 1.0; // 100% of the current animation segment float middle; Vector2 start(0, bt->values[idx].value.value); @@ -2734,7 +2738,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for colinearity + return false; //beyond allowed error for collinearity } if (p_norm != Vector3() && Math::acos(pd.normalized().dot(p_norm)) > p_alowed_angular_err) { @@ -2824,7 +2828,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons real_t d = Geometry3D::get_closest_point_to_segment(v1, s).distance_to(v1); if (d > pd.length() * p_alowed_linear_err) { - return false; //beyond allowed error for colinearity + return false; //beyond allowed error for collinearity } t[2] = (d1 - d0) / (d2 - d0); @@ -2836,7 +2840,7 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons erase = true; } else { erase = true; - real_t lt = -1; + real_t lt = -1.0; for (int j = 0; j < 3; j++) { //search for t on first, one must be it if (t[j] != -1) { @@ -2919,11 +2923,7 @@ void Animation::optimize(float p_allowed_linear_err, float p_allowed_angular_err } } -Animation::Animation() { - step = 0.1; - loop = false; - length = 1; -} +Animation::Animation() {} Animation::~Animation() { for (int i = 0; i < tracks.size(); i++) { diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 650a54ebfc..66bc71c834 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -65,28 +65,19 @@ public: private: struct Track { - TrackType type; - InterpolationType interpolation; - bool loop_wrap; + TrackType type = TrackType::TYPE_ANIMATION; + InterpolationType interpolation = INTERPOLATION_LINEAR; + bool loop_wrap = true; NodePath path; // path to something - bool imported; - bool enabled; - Track() { - interpolation = INTERPOLATION_LINEAR; - imported = false; - loop_wrap = true; - enabled = true; - } + bool imported = false; + bool enabled = true; + Track() {} virtual ~Track() {} }; struct Key { - float transition; - float time; // time in secs - Key() { - transition = 1; - time = 0; - } + float transition = 1.0; + float time = 0.0; // time in secs }; // transform key holds either Vector3 or Quaternion @@ -112,13 +103,12 @@ private: /* PROPERTY VALUE TRACK */ struct ValueTrack : public Track { - UpdateMode update_mode; - bool update_on_seek; + UpdateMode update_mode = UPDATE_CONTINUOUS; + bool update_on_seek = false; Vector<TKey<Variant>> values; ValueTrack() { type = TYPE_VALUE; - update_mode = UPDATE_CONTINUOUS; } }; @@ -139,7 +129,7 @@ private: struct BezierKey { Vector2 in_handle; //relative (x always <0) Vector2 out_handle; //relative (x always >0) - float value; + float value = 0.0; }; struct BezierTrack : public Track { @@ -154,11 +144,9 @@ private: struct AudioKey { RES stream; - float start_offset; //offset from start - float end_offset; //offset from end, if 0 then full length or infinite + float start_offset = 0.0; //offset from start + float end_offset = 0.0; //offset from end, if 0 then full length or infinite AudioKey() { - start_offset = 0; - end_offset = 0; } }; @@ -217,9 +205,9 @@ private: _FORCE_INLINE_ void _value_track_get_key_indices_in_range(const ValueTrack *vt, float from_time, float to_time, List<int> *p_indices) const; _FORCE_INLINE_ void _method_track_get_key_indices_in_range(const MethodTrack *mt, float from_time, float to_time, List<int> *p_indices) const; - float length; - float step; - bool loop; + float length = 1.0; + float step = 0.1; + bool loop = false; // bind helpers private: @@ -264,6 +252,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + static void _bind_methods(); public: diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index 600a859894..06a91fb2f8 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -403,11 +403,7 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in } } -AudioStreamPlaybackSample::AudioStreamPlaybackSample() { - active = false; - offset = 0; - sign = 1; -} +AudioStreamPlaybackSample::AudioStreamPlaybackSample() {} ///////////////////// @@ -651,16 +647,7 @@ void AudioStreamSample::_bind_methods() { BIND_ENUM_CONSTANT(LOOP_BACKWARD); } -AudioStreamSample::AudioStreamSample() { - format = FORMAT_8_BITS; - loop_mode = LOOP_DISABLED; - stereo = false; - loop_begin = 0; - loop_end = 0; - mix_rate = 44100; - data = nullptr; - data_bytes = 0; -} +AudioStreamSample::AudioStreamSample() {} AudioStreamSample::~AudioStreamSample() { if (data) { diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index d91cdef57d..70b8ba79ad 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,19 +44,19 @@ class AudioStreamPlaybackSample : public AudioStreamPlayback { }; struct IMA_ADPCM_State { - int16_t step_index; - int32_t predictor; + int16_t step_index = 0; + int32_t predictor = 0; /* values at loop point */ - int16_t loop_step_index; - int32_t loop_predictor; - int32_t last_nibble; - int32_t loop_pos; - int32_t window_ofs; + int16_t loop_step_index = 0; + int32_t loop_predictor = 0; + int32_t last_nibble = 0; + int32_t loop_pos = 0; + int32_t window_ofs = 0; } ima_adpcm[2]; - int64_t offset; - int sign; - bool active; + int64_t offset = 0; + int sign = 1; + bool active = false; friend class AudioStreamSample; Ref<AudioStreamSample> base; @@ -103,14 +103,14 @@ private: DATA_PAD = 16 //padding for interpolation }; - Format format; - LoopMode loop_mode; - bool stereo; - int loop_begin; - int loop_end; - int mix_rate; - void *data; - uint32_t data_bytes; + Format format = FORMAT_8_BITS; + LoopMode loop_mode = LOOP_DISABLED; + bool stereo = false; + int loop_begin = 0; + int loop_end = 0; + int mix_rate = 44100; + void *data = nullptr; + uint32_t data_bytes = 0; protected: static void _bind_methods(); diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index d07447179d..3cc1af59ae 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,7 +43,7 @@ void BitMap::create(const Size2 &p_size) { } void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) { - ERR_FAIL_COND(p_image.is_null() || p_image->empty()); + ERR_FAIL_COND(p_image.is_null() || p_image->is_empty()); Ref<Image> img = p_image->duplicate(); img->convert(Image::FORMAT_LA8); ERR_FAIL_COND(img->get_format() != Image::FORMAT_LA8); @@ -285,7 +285,7 @@ Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) +---+---+ | 4 | | +---+---+ - this normally go RIGHT, but if its coming from RIGHT, it should go LEFT + this normally go RIGHT, but if it's coming from RIGHT, it should go LEFT */ if (case6s.has(Point2i(curx, cury))) { //found, so we go left, and delete from case6s; @@ -346,7 +346,7 @@ static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) { } int index = -1; - float dist = 0; + float dist = 0.0; //not looping first and last point for (size_t i = 1, size = v.size(); i < size - 1; ++i) { float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]); @@ -406,8 +406,8 @@ static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, struct FillBitsStackEntry { Point2i pos; - int i; - int j; + int i = 0; + int j = 0; }; static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) { @@ -677,9 +677,6 @@ void BitMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data"); } -BitMap::BitMap() { - width = 0; - height = 0; -} +BitMap::BitMap() {} ////////////////////////////////////// diff --git a/scene/resources/bit_map.h b/scene/resources/bit_map.h index 56ff72c094..68fd0b999a 100644 --- a/scene/resources/bit_map.h +++ b/scene/resources/bit_map.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -40,8 +40,8 @@ class BitMap : public Resource { OBJ_SAVE_TYPE(BitMap); Vector<uint8_t> bitmask; - int width; - int height; + int width = 0; + int height = 0; Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const; diff --git a/scene/resources/box_shape_3d.cpp b/scene/resources/box_shape_3d.cpp index e1c8a377c0..6e7adc0bd7 100644 --- a/scene/resources/box_shape_3d.cpp +++ b/scene/resources/box_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,8 +34,8 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const { Vector<Vector3> lines; AABB aabb; - aabb.position = -get_extents(); - aabb.size = aabb.position * -2; + aabb.position = -size / 2; + aabb.size = size; for (int i = 0; i < 12; i++) { Vector3 a, b; @@ -48,33 +48,32 @@ Vector<Vector3> BoxShape3D::get_debug_mesh_lines() const { } real_t BoxShape3D::get_enclosing_radius() const { - return extents.length(); + return size.length() / 2; } void BoxShape3D::_update_shape() { - PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), extents); + PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), size / 2); Shape3D::_update_shape(); } -void BoxShape3D::set_extents(const Vector3 &p_extents) { - extents = p_extents; +void BoxShape3D::set_size(const Vector3 &p_size) { + size = p_size; _update_shape(); notify_change_to_owners(); - _change_notify("extents"); } -Vector3 BoxShape3D::get_extents() const { - return extents; +Vector3 BoxShape3D::get_size() const { + return size; } void BoxShape3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_extents", "extents"), &BoxShape3D::set_extents); - ClassDB::bind_method(D_METHOD("get_extents"), &BoxShape3D::get_extents); + ClassDB::bind_method(D_METHOD("set_size", "size"), &BoxShape3D::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &BoxShape3D::get_size); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); } BoxShape3D::BoxShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_BOX)) { - set_extents(Vector3(1, 1, 1)); + set_size(Vector3(2, 2, 2)); } diff --git a/scene/resources/box_shape_3d.h b/scene/resources/box_shape_3d.h index fe634ce568..fce05d61ed 100644 --- a/scene/resources/box_shape_3d.h +++ b/scene/resources/box_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,7 +35,7 @@ class BoxShape3D : public Shape3D { GDCLASS(BoxShape3D, Shape3D); - Vector3 extents; + Vector3 size; protected: static void _bind_methods(); @@ -43,8 +43,8 @@ protected: virtual void _update_shape() override; public: - void set_extents(const Vector3 &p_extents); - Vector3 get_extents() const; + void set_size(const Vector3 &p_size); + Vector3 get_size() const; virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 6b6ed51ed0..34c6bc05bc 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,7 +41,7 @@ RID CameraEffects::get_rid() const { void CameraEffects::set_dof_blur_far_enabled(bool p_enabled) { dof_blur_far_enabled = p_enabled; _update_dof_blur(); - _change_notify(); + notify_property_list_changed(); } bool CameraEffects::is_dof_blur_far_enabled() const { @@ -69,7 +69,7 @@ float CameraEffects::get_dof_blur_far_transition() const { void CameraEffects::set_dof_blur_near_enabled(bool p_enabled) { dof_blur_near_enabled = p_enabled; _update_dof_blur(); - _change_notify(); + notify_property_list_changed(); } bool CameraEffects::is_dof_blur_near_enabled() const { @@ -120,6 +120,7 @@ void CameraEffects::_update_dof_blur() { void CameraEffects::set_override_exposure_enabled(bool p_enabled) { override_exposure_enabled = p_enabled; _update_override_exposure(); + notify_property_list_changed(); } bool CameraEffects::is_override_exposure_enabled() const { @@ -144,6 +145,14 @@ void CameraEffects::_update_override_exposure() { // Private methods, constructor and destructor +void CameraEffects::_validate_property(PropertyInfo &property) const { + if ((!dof_blur_far_enabled && (property.name == "dof_blur_far_distance" || property.name == "dof_blur_far_transition")) || + (!dof_blur_near_enabled && (property.name == "dof_blur_near_distance" || property.name == "dof_blur_near_transition")) || + (!override_exposure_enabled && property.name == "override_exposure")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void CameraEffects::_bind_methods() { // DOF blur diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h index 9a26f3d0b2..b9338f4806 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_effects.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,12 +42,12 @@ private: // DOF blur bool dof_blur_far_enabled = false; - float dof_blur_far_distance = 10; - float dof_blur_far_transition = 5; + float dof_blur_far_distance = 10.0; + float dof_blur_far_transition = 5.0; bool dof_blur_near_enabled = false; - float dof_blur_near_distance = 2; - float dof_blur_near_transition = 1; + float dof_blur_near_distance = 2.0; + float dof_blur_near_transition = 1.0; float dof_blur_amount = 0.1; void _update_dof_blur(); @@ -59,6 +59,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: virtual RID get_rid() const override; diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index e519970f38..e5edba8a67 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,12 +36,13 @@ Vector<Vector2> CapsuleShape2D::_get_points() const { Vector<Vector2> points; + const real_t turn_step = Math_TAU / 24.0; for (int i = 0; i < 24; i++) { Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5); - points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs); + points.push_back(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * get_radius() + ofs); if (i == 6 || i == 18) { - points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs); + points.push_back(Vector2(Math::sin(i * turn_step), Math::cos(i * turn_step)) * get_radius() - ofs); } } @@ -84,6 +85,11 @@ void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } Rect2 CapsuleShape2D::get_rect() const { @@ -111,7 +117,5 @@ void CapsuleShape2D::_bind_methods() { CapsuleShape2D::CapsuleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->capsule_shape_create()) { - radius = 10; - height = 20; _update_shape(); } diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h index 1caa6c68b8..439b67e8c3 100644 --- a/scene/resources/capsule_shape_2d.h +++ b/scene/resources/capsule_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,8 +36,8 @@ class CapsuleShape2D : public Shape2D { GDCLASS(CapsuleShape2D, Shape2D); - real_t height; - real_t radius; + real_t height = 20.0; + real_t radius = 10.0; void _update_shape(); Vector<Vector2> _get_points() const; diff --git a/scene/resources/capsule_shape_3d.cpp b/scene/resources/capsule_shape_3d.cpp index 5da7f682e5..226fe1ecd2 100644 --- a/scene/resources/capsule_shape_3d.cpp +++ b/scene/resources/capsule_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -82,7 +82,6 @@ void CapsuleShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float CapsuleShape3D::get_radius() const { @@ -93,7 +92,6 @@ void CapsuleShape3D::set_height(float p_height) { height = p_height; _update_shape(); notify_change_to_owners(); - _change_notify("height"); } float CapsuleShape3D::get_height() const { @@ -112,7 +110,5 @@ void CapsuleShape3D::_bind_methods() { CapsuleShape3D::CapsuleShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CAPSULE)) { - radius = 1.0; - height = 1.0; _update_shape(); } diff --git a/scene/resources/capsule_shape_3d.h b/scene/resources/capsule_shape_3d.h index 432ca5654e..25645ecf9d 100644 --- a/scene/resources/capsule_shape_3d.h +++ b/scene/resources/capsule_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,8 +35,8 @@ class CapsuleShape3D : public Shape3D { GDCLASS(CapsuleShape3D, Shape3D); - float radius; - float height; + float radius = 1.0; + float height = 1.0; protected: static void _bind_methods(); diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index dc1bf3b185..f06bc4248d 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,17 +71,22 @@ real_t CircleShape2D::get_enclosing_radius() const { void CircleShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector<Vector2> points; + const real_t turn_step = Math_TAU / 24.0; for (int i = 0; i < 24; i++) { - points.push_back(Vector2(Math::cos(i * Math_PI * 2 / 24.0), Math::sin(i * Math_PI * 2 / 24.0)) * get_radius()); + points.push_back(Vector2(Math::cos(i * turn_step), Math::sin(i * turn_step)) * get_radius()); } Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } CircleShape2D::CircleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->circle_shape_create()) { - radius = 10; _update_shape(); } diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h index ac8757e781..333f299236 100644 --- a/scene/resources/circle_shape_2d.h +++ b/scene/resources/circle_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class CircleShape2D : public Shape2D { GDCLASS(CircleShape2D, Shape2D); - real_t radius; + real_t radius = 10.0; void _update_shape(); protected: diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp index eecf8afa8f..0c767c8a52 100644 --- a/scene/resources/concave_polygon_shape_2d.cpp +++ b/scene/resources/concave_polygon_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -98,7 +98,7 @@ Rect2 ConcavePolygonShape2D::get_rect() const { real_t ConcavePolygonShape2D::get_enclosing_radius() const { Vector<Vector2> data = get_segments(); const Vector2 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h index df8cc9920f..98ae341e97 100644 --- a/scene/resources/concave_polygon_shape_2d.h +++ b/scene/resources/concave_polygon_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/concave_polygon_shape_3d.cpp b/scene/resources/concave_polygon_shape_3d.cpp index 7cbafcbc4d..3fed700383 100644 --- a/scene/resources/concave_polygon_shape_3d.cpp +++ b/scene/resources/concave_polygon_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,13 +35,12 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const { Set<DrawEdge> edges; - Vector<Vector3> data = get_faces(); - int datalen = data.size(); - ERR_FAIL_COND_V((datalen % 3) != 0, Vector<Vector3>()); + int index_count = faces.size(); + ERR_FAIL_COND_V((index_count % 3) != 0, Vector<Vector3>()); - const Vector3 *r = data.ptr(); + const Vector3 *r = faces.ptr(); - for (int i = 0; i < datalen; i += 3) { + for (int i = 0; i < index_count; i += 3) { for (int j = 0; j < 3; j++) { DrawEdge de(r[i + j], r[i + ((j + 1) % 3)]); edges.insert(de); @@ -63,7 +62,7 @@ Vector<Vector3> ConcavePolygonShape3D::get_debug_mesh_lines() const { real_t ConcavePolygonShape3D::get_enclosing_radius() const { Vector<Vector3> data = get_faces(); const Vector3 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } @@ -71,22 +70,46 @@ real_t ConcavePolygonShape3D::get_enclosing_radius() const { } void ConcavePolygonShape3D::_update_shape() { + Dictionary d; + d["faces"] = faces; + d["backface_collision"] = backface_collision; + PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), d); + Shape3D::_update_shape(); } void ConcavePolygonShape3D::set_faces(const Vector<Vector3> &p_faces) { - PhysicsServer3D::get_singleton()->shape_set_data(get_shape(), p_faces); + faces = p_faces; + _update_shape(); notify_change_to_owners(); } Vector<Vector3> ConcavePolygonShape3D::get_faces() const { - return PhysicsServer3D::get_singleton()->shape_get_data(get_shape()); + return faces; +} + +void ConcavePolygonShape3D::set_backface_collision_enabled(bool p_enabled) { + backface_collision = p_enabled; + + if (!faces.is_empty()) { + _update_shape(); + notify_change_to_owners(); + } +} + +bool ConcavePolygonShape3D::is_backface_collision_enabled() const { + return backface_collision; } void ConcavePolygonShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape3D::set_faces); ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape3D::get_faces); + + ClassDB::bind_method(D_METHOD("set_backface_collision_enabled", "enabled"), &ConcavePolygonShape3D::set_backface_collision_enabled); + ClassDB::bind_method(D_METHOD("is_backface_collision_enabled"), &ConcavePolygonShape3D::is_backface_collision_enabled); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "backface_collision"), "set_backface_collision_enabled", "is_backface_collision_enabled"); } ConcavePolygonShape3D::ConcavePolygonShape3D() : diff --git a/scene/resources/concave_polygon_shape_3d.h b/scene/resources/concave_polygon_shape_3d.h index c17765b9ef..bb28359dcc 100644 --- a/scene/resources/concave_polygon_shape_3d.h +++ b/scene/resources/concave_polygon_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,6 +36,9 @@ class ConcavePolygonShape3D : public Shape3D { GDCLASS(ConcavePolygonShape3D, Shape3D); + Vector<Vector3> faces; + bool backface_collision = false; + struct DrawEdge { Vector3 a; Vector3 b; @@ -65,6 +68,9 @@ public: void set_faces(const Vector<Vector3> &p_faces); Vector<Vector3> get_faces() const; + void set_backface_collision_enabled(bool p_enabled); + bool is_backface_collision_enabled() const; + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index 2b7531c630..6e56f6e7fc 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -72,9 +72,18 @@ void ConvexPolygonShape2D::_bind_methods() { } void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) { + if (points.size() < 3) { + return; + } + Vector<Color> col; col.push_back(p_color); RenderingServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col); + if (is_collision_outline_enabled()) { + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col); + // Draw the last segment as it's not drawn by `canvas_item_add_polyline()`. + RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color); + } } Rect2 ConvexPolygonShape2D::get_rect() const { @@ -91,7 +100,7 @@ Rect2 ConvexPolygonShape2D::get_rect() const { } real_t ConvexPolygonShape2D::get_enclosing_radius() const { - real_t r = 0; + real_t r = 0.0; for (int i(0); i < get_points().size(); i++) { r = MAX(get_points()[i].length_squared(), r); } diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h index 294157bec5..1813b608bd 100644 --- a/scene/resources/convex_polygon_shape_2d.h +++ b/scene/resources/convex_polygon_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/convex_polygon_shape_3d.cpp b/scene/resources/convex_polygon_shape_3d.cpp index 29549e1114..9e030bc077 100644 --- a/scene/resources/convex_polygon_shape_3d.cpp +++ b/scene/resources/convex_polygon_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -56,7 +56,7 @@ Vector<Vector3> ConvexPolygonShape3D::get_debug_mesh_lines() const { real_t ConvexPolygonShape3D::get_enclosing_radius() const { Vector<Vector3> data = get_points(); const Vector3 *read = data.ptr(); - real_t r = 0; + real_t r = 0.0; for (int i(0); i < data.size(); i++) { r = MAX(read[i].length_squared(), r); } diff --git a/scene/resources/convex_polygon_shape_3d.h b/scene/resources/convex_polygon_shape_3d.h index f436d2f5d4..edd127c8f4 100644 --- a/scene/resources/convex_polygon_shape_3d.h +++ b/scene/resources/convex_polygon_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index de076670cf..bc479e557a 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,11 +47,6 @@ static _FORCE_INLINE_ T _bezier_interp(real_t t, T start, T control_1, T control const char *Curve::SIGNAL_RANGE_CHANGED = "range_changed"; Curve::Curve() { - _bake_resolution = 100; - _baked_cache_dirty = false; - _min_value = 0; - _max_value = 1; - _minmax_set_once = 0b00; } int Curve::add_point(Vector2 p_pos, real_t left_tangent, real_t right_tangent, TangentMode left_mode, TangentMode right_mode) { @@ -602,7 +597,7 @@ void Curve2D::remove_point(int p_index) { } void Curve2D::clear_points() { - if (!points.empty()) { + if (!points.is_empty()) { points.clear(); baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); @@ -683,7 +678,7 @@ void Curve2D::_bake() const { for (int i = 0; i < points.size() - 1; i++) { float step = 0.1; // at least 10 substeps ought to be enough? - float p = 0; + float p = 0.0; while (p < 1.0) { float np = p + step; @@ -993,12 +988,9 @@ void Curve2D::_bind_methods() { } Curve2D::Curve2D() { - baked_cache_dirty = false; - baked_max_ofs = 0; /* add_point(Vector2(-1,0,0)); add_point(Vector2(0,2,0)); add_point(Vector2(0,3,5));*/ - bake_interval = 5; } /***********************************************************************************/ @@ -1087,7 +1079,7 @@ void Curve3D::remove_point(int p_index) { } void Curve3D::clear_points() { - if (!points.empty()) { + if (!points.is_empty()) { points.clear(); baked_cache_dirty = true; emit_signal(CoreStringNames::get_singleton()->changed); @@ -1178,7 +1170,7 @@ void Curve3D::_bake() const { for (int i = 0; i < points.size() - 1; i++) { float step = 0.1; // at least 10 substeps ought to be enough? - float p = 0; + float p = 0.0; while (p < 1.0) { float np = p + step; @@ -1669,11 +1661,7 @@ void Curve3D::_bind_methods() { } Curve3D::Curve3D() { - baked_cache_dirty = false; - baked_max_ofs = 0; /* add_point(Vector3(-1,0,0)); add_point(Vector3(0,2,0)); add_point(Vector3(0,3,5));*/ - bake_interval = 0.2; - up_vector_enabled = true; } diff --git a/scene/resources/curve.h b/scene/resources/curve.h index 6c5f4b7057..402c893cd8 100644 --- a/scene/resources/curve.h +++ b/scene/resources/curve.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,21 +51,17 @@ public: struct Point { Vector2 pos; - real_t left_tangent; - real_t right_tangent; - TangentMode left_mode; - TangentMode right_mode; + real_t left_tangent = 0.0; + real_t right_tangent = 0.0; + TangentMode left_mode = TANGENT_FREE; + TangentMode right_mode = TANGENT_FREE; Point() { - left_tangent = 0; - right_tangent = 0; - left_mode = TANGENT_FREE; - right_mode = TANGENT_FREE; } Point(Vector2 p_pos, - real_t p_left = 0, - real_t p_right = 0, + real_t p_left = 0.0, + real_t p_right = 0.0, TangentMode p_left_mode = TANGENT_FREE, TangentMode p_right_mode = TANGENT_FREE) { pos = p_pos; @@ -137,12 +133,12 @@ private: void mark_dirty(); Vector<Point> _points; - bool _baked_cache_dirty; + bool _baked_cache_dirty = false; Vector<real_t> _baked_cache; - int _bake_resolution; - float _min_value; - float _max_value; - int _minmax_set_once; // Encodes whether min and max have been set a first time, first bit for min and second for max. + int _bake_resolution = 100; + float _min_value = 0.0; + float _max_value = 1.0; + int _minmax_set_once = 0b00; // Encodes whether min and max have been set a first time, first bit for min and second for max. }; VARIANT_ENUM_CAST(Curve::TangentMode) @@ -159,17 +155,17 @@ class Curve2D : public Resource { Vector<Point> points; struct BakedPoint { - float ofs; + float ofs = 0.0; Vector2 point; }; - mutable bool baked_cache_dirty; + mutable bool baked_cache_dirty = false; mutable PackedVector2Array baked_point_cache; - mutable float baked_max_ofs; + mutable float baked_max_ofs = 0.0; void _bake() const; - float bake_interval; + float bake_interval = 5.0; void _bake_segment2d(Map<float, Vector2> &r_bake, float p_begin, float p_end, const Vector2 &p_a, const Vector2 &p_out, const Vector2 &p_b, const Vector2 &p_in, int p_depth, int p_max_depth, float p_tol) const; Dictionary _get_data() const; @@ -214,28 +210,26 @@ class Curve3D : public Resource { Vector3 in; Vector3 out; Vector3 pos; - float tilt; - - Point() { tilt = 0; } + float tilt = 0.0; }; Vector<Point> points; struct BakedPoint { - float ofs; + float ofs = 0.0; Vector3 point; }; - mutable bool baked_cache_dirty; + mutable bool baked_cache_dirty = false; mutable PackedVector3Array baked_point_cache; mutable PackedFloat32Array baked_tilt_cache; mutable PackedVector3Array baked_up_vector_cache; - mutable float baked_max_ofs; + mutable float baked_max_ofs = 0.0; void _bake() const; - float bake_interval; - bool up_vector_enabled; + float bake_interval = 0.2; + bool up_vector_enabled = true; void _bake_segment3d(Map<float, Vector3> &r_bake, float p_begin, float p_end, const Vector3 &p_a, const Vector3 &p_out, const Vector3 &p_b, const Vector3 &p_in, int p_depth, int p_max_depth, float p_tol) const; Dictionary _get_data() const; diff --git a/scene/resources/cylinder_shape_3d.cpp b/scene/resources/cylinder_shape_3d.cpp index bb8c27a60d..63bdc8d26d 100644 --- a/scene/resources/cylinder_shape_3d.cpp +++ b/scene/resources/cylinder_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -75,7 +75,6 @@ void CylinderShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float CylinderShape3D::get_radius() const { @@ -86,7 +85,6 @@ void CylinderShape3D::set_height(float p_height) { height = p_height; _update_shape(); notify_change_to_owners(); - _change_notify("height"); } float CylinderShape3D::get_height() const { @@ -105,7 +103,5 @@ void CylinderShape3D::_bind_methods() { CylinderShape3D::CylinderShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_CYLINDER)) { - radius = 1.0; - height = 2.0; _update_shape(); } diff --git a/scene/resources/cylinder_shape_3d.h b/scene/resources/cylinder_shape_3d.h index e579e1f7cf..d1b8364672 100644 --- a/scene/resources/cylinder_shape_3d.h +++ b/scene/resources/cylinder_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,8 +35,8 @@ class CylinderShape3D : public Shape3D { GDCLASS(CylinderShape3D, Shape3D); - float radius; - float height; + float radius = 1.0; + float height = 2.0; protected: static void _bind_methods(); diff --git a/scene/resources/default_theme/bar_arrow.png b/scene/resources/default_theme/bar_arrow.png Binary files differnew file mode 100644 index 0000000000..7cf146b8da --- /dev/null +++ b/scene/resources/default_theme/bar_arrow.png diff --git a/scene/resources/default_theme/checked_disabled.png b/scene/resources/default_theme/checked_disabled.png Binary files differnew file mode 100644 index 0000000000..70549e2edc --- /dev/null +++ b/scene/resources/default_theme/checked_disabled.png diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2de28b5e5c..85d097aa19 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,10 +43,10 @@ typedef Map<const void *, Ref<ImageTexture>> TexCacheMap; static TexCacheMap *tex_cache; -static float scale = 1; +static float scale = 1.0; template <class T> -static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_botton, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1, bool p_draw_center = true) { +static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) { Ref<ImageTexture> texture; if (tex_cache->has(p_src)) { @@ -64,14 +64,14 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl Ref<StyleBoxTexture> style(memnew(StyleBoxTexture)); style->set_texture(texture); - style->set_margin_size(MARGIN_LEFT, p_left * scale); - style->set_margin_size(MARGIN_RIGHT, p_right * scale); - style->set_margin_size(MARGIN_BOTTOM, p_botton * scale); - style->set_margin_size(MARGIN_TOP, p_top * scale); - style->set_default_margin(MARGIN_LEFT, p_margin_left * scale); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale); - style->set_default_margin(MARGIN_BOTTOM, p_margin_botton * scale); - style->set_default_margin(MARGIN_TOP, p_margin_top * scale); + style->set_margin_size(SIDE_LEFT, p_left * scale); + style->set_margin_size(SIDE_RIGHT, p_right * scale); + style->set_margin_size(SIDE_BOTTOM, p_bottom * scale); + style->set_margin_size(SIDE_TOP, p_top * scale); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); style->set_draw_center(p_draw_center); return style; @@ -80,19 +80,19 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src, float p_left, float p_top, fl static Ref<StyleBoxFlat> make_flat_stylebox(Color p_color, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBoxFlat> style(memnew(StyleBoxFlat)); style->set_bg_color(p_color); - style->set_default_margin(MARGIN_LEFT, p_margin_left * scale); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale); - style->set_default_margin(MARGIN_BOTTOM, p_margin_bottom * scale); - style->set_default_margin(MARGIN_TOP, p_margin_top * scale); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); return style; } -static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_botton) { - p_sbox->set_expand_margin_size(MARGIN_LEFT, p_left * scale); - p_sbox->set_expand_margin_size(MARGIN_TOP, p_top * scale); - p_sbox->set_expand_margin_size(MARGIN_RIGHT, p_right * scale); - p_sbox->set_expand_margin_size(MARGIN_BOTTOM, p_botton * scale); +static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox, float p_left, float p_top, float p_right, float p_bottom) { + p_sbox->set_expand_margin_size(SIDE_LEFT, p_left * scale); + p_sbox->set_expand_margin_size(SIDE_TOP, p_top * scale); + p_sbox->set_expand_margin_size(SIDE_RIGHT, p_right * scale); + p_sbox->set_expand_margin_size(SIDE_BOTTOM, p_bottom * scale); return p_sbox; } @@ -114,7 +114,8 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, } Ref<ImageTexture> texture(memnew(ImageTexture)); - Ref<Image> img = p_texture->get_data(); + Ref<Image> img = p_texture->get_image(); + img = img->duplicate(); if (p_flip_y) { img->flip_y(); @@ -127,13 +128,45 @@ static Ref<Texture2D> flip_icon(Ref<Texture2D> p_texture, bool p_flip_y = false, return texture; } -static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_botton = -1) { +static Ref<FontData> make_font(int p_height, int p_ascent, int p_charcount, const int *p_char_rects, int p_kerning_count, const int *p_kernings, int p_w, int p_h, const unsigned char *p_img) { + Ref<FontData> font(memnew(FontData)); + font->new_bitmap(p_height, p_ascent, p_height); + + Ref<Image> image = memnew(Image(p_img)); + Ref<ImageTexture> tex = memnew(ImageTexture); + tex->create_from_image(image); + + font->bitmap_add_texture(tex); + + for (int i = 0; i < p_charcount; i++) { + const int *c = &p_char_rects[i * 8]; + + int chr = c[0]; + Rect2 frect; + frect.position.x = c[1]; + frect.position.y = c[2]; + frect.size.x = c[3]; + frect.size.y = c[4]; + Point2 align(c[6], c[5]); + int advance = c[7]; + + font->bitmap_add_char(chr, 0, frect, align, advance); + } + + for (int i = 0; i < p_kerning_count; i++) { + font->bitmap_add_kerning_pair(p_kernings[i * 3 + 0], p_kernings[i * 3 + 1], p_kernings[i * 3 + 2]); + } + + return font; +} + +static Ref<StyleBox> make_empty_stylebox(float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1) { Ref<StyleBox> style(memnew(StyleBoxEmpty)); - style->set_default_margin(MARGIN_LEFT, p_margin_left * scale); - style->set_default_margin(MARGIN_RIGHT, p_margin_right * scale); - style->set_default_margin(MARGIN_BOTTOM, p_margin_botton * scale); - style->set_default_margin(MARGIN_TOP, p_margin_top * scale); + style->set_default_margin(SIDE_LEFT, p_margin_left * scale); + style->set_default_margin(SIDE_RIGHT, p_margin_right * scale); + style->set_default_margin(SIDE_BOTTOM, p_margin_bottom * scale); + style->set_default_margin(SIDE_TOP, p_margin_top * scale); return style; } @@ -146,12 +179,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // Font Colors Color control_font_color = Color(0.88, 0.88, 0.88); - Color control_font_color_lower = Color(0.63, 0.63, 0.63); - Color control_font_color_low = Color(0.69, 0.69, 0.69); - Color control_font_color_hover = Color(0.94, 0.94, 0.94); - Color control_font_color_disabled = Color(0.9, 0.9, 0.9, 0.2); - Color control_font_color_pressed = Color(1, 1, 1); - Color font_color_selection = Color(0.49, 0.49, 0.49); + Color control_font_lower_color = Color(0.63, 0.63, 0.63); + Color control_font_low_color = Color(0.69, 0.69, 0.69); + Color control_font_hover_color = Color(0.94, 0.94, 0.94); + Color control_font_disabled_color = Color(0.9, 0.9, 0.9, 0.2); + Color control_font_pressed_color = Color(1, 1, 1); + + Color control_selection_color = Color(0.49, 0.49, 0.49); // Panel @@ -162,7 +196,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> focus = make_stylebox(focus_png, 5, 5, 5, 5); for (int i = 0; i < 4; i++) { - focus->set_expand_margin_size(Margin(i), 1 * scale); + focus->set_expand_margin_size(Side(i), 1 * scale); } // Button @@ -184,10 +218,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("outline_size", "Button", 0 * scale); theme->set_color("font_color", "Button", control_font_color); - theme->set_color("font_color_pressed", "Button", control_font_color_pressed); - theme->set_color("font_color_hover", "Button", control_font_color_hover); - theme->set_color("font_color_disabled", "Button", control_font_color_disabled); - theme->set_color("font_outline_modulate", "Button", Color(1, 1, 1)); + theme->set_color("font_pressed_color", "Button", control_font_pressed_color); + theme->set_color("font_hover_color", "Button", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "Button", control_font_pressed_color); + theme->set_color("font_disabled_color", "Button", control_font_disabled_color); + theme->set_color("font_outline_color", "Button", Color(1, 1, 1)); + + theme->set_color("icon_normal_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_pressed_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_hover_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_hover_pressed_color", "Button", Color(1, 1, 1, 1)); + theme->set_color("icon_disabled_color", "Button", Color(1, 1, 1, 1)); theme->set_constant("hseparation", "Button", 2 * scale); @@ -199,9 +240,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "LinkButton", -1); theme->set_color("font_color", "LinkButton", control_font_color); - theme->set_color("font_color_pressed", "LinkButton", control_font_color_pressed); - theme->set_color("font_color_hover", "LinkButton", control_font_color_hover); + theme->set_color("font_pressed_color", "LinkButton", control_font_pressed_color); + theme->set_color("font_hover_color", "LinkButton", control_font_hover_color); + theme->set_color("font_outline_color", "LinkButton", Color(1, 1, 1)); + theme->set_constant("outline_size", "LinkButton", 0); theme->set_constant("underline_spacing", "LinkButton", 2 * scale); // ColorPickerButton @@ -216,11 +259,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "ColorPickerButton", -1); theme->set_color("font_color", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_pressed", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); - theme->set_color("font_color_hover", "ColorPickerButton", Color(1, 1, 1, 1)); - theme->set_color("font_color_disabled", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); + theme->set_color("font_pressed_color", "ColorPickerButton", Color(0.8, 0.8, 0.8, 1)); + theme->set_color("font_hover_color", "ColorPickerButton", Color(1, 1, 1, 1)); + theme->set_color("font_disabled_color", "ColorPickerButton", Color(0.9, 0.9, 0.9, 0.3)); + theme->set_color("font_outline_color", "ColorPickerButton", Color(1, 1, 1)); theme->set_constant("hseparation", "ColorPickerButton", 2 * scale); + theme->set_constant("outline_size", "ColorPickerButton", 0); // OptionButton @@ -253,12 +298,14 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "OptionButton", -1); theme->set_color("font_color", "OptionButton", control_font_color); - theme->set_color("font_color_pressed", "OptionButton", control_font_color_pressed); - theme->set_color("font_color_hover", "OptionButton", control_font_color_hover); - theme->set_color("font_color_disabled", "OptionButton", control_font_color_disabled); + theme->set_color("font_pressed_color", "OptionButton", control_font_pressed_color); + theme->set_color("font_hover_color", "OptionButton", control_font_hover_color); + theme->set_color("font_disabled_color", "OptionButton", control_font_disabled_color); + theme->set_color("font_outline_color", "OptionButton", Color(1, 1, 1)); theme->set_constant("hseparation", "OptionButton", 2 * scale); theme->set_constant("arrow_margin", "OptionButton", 2 * scale); + theme->set_constant("outline_size", "OptionButton", 0); // MenuButton @@ -272,24 +319,26 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "MenuButton", -1); theme->set_color("font_color", "MenuButton", control_font_color); - theme->set_color("font_color_pressed", "MenuButton", control_font_color_pressed); - theme->set_color("font_color_hover", "MenuButton", control_font_color_hover); - theme->set_color("font_color_disabled", "MenuButton", Color(1, 1, 1, 0.3)); + theme->set_color("font_pressed_color", "MenuButton", control_font_pressed_color); + theme->set_color("font_hover_color", "MenuButton", control_font_hover_color); + theme->set_color("font_disabled_color", "MenuButton", Color(1, 1, 1, 0.3)); + theme->set_color("font_outline_color", "MenuButton", Color(1, 1, 1)); theme->set_constant("hseparation", "MenuButton", 3 * scale); + theme->set_constant("outline_size", "MenuButton", 0); // CheckBox Ref<StyleBox> cbx_empty = memnew(StyleBoxEmpty); - cbx_empty->set_default_margin(MARGIN_LEFT, 4 * scale); - cbx_empty->set_default_margin(MARGIN_RIGHT, 4 * scale); - cbx_empty->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cbx_empty->set_default_margin(SIDE_LEFT, 4 * scale); + cbx_empty->set_default_margin(SIDE_RIGHT, 4 * scale); + cbx_empty->set_default_margin(SIDE_TOP, 4 * scale); + cbx_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); Ref<StyleBox> cbx_focus = focus; - cbx_focus->set_default_margin(MARGIN_LEFT, 4 * scale); - cbx_focus->set_default_margin(MARGIN_RIGHT, 4 * scale); - cbx_focus->set_default_margin(MARGIN_TOP, 4 * scale); - cbx_focus->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cbx_focus->set_default_margin(SIDE_LEFT, 4 * scale); + cbx_focus->set_default_margin(SIDE_RIGHT, 4 * scale); + cbx_focus->set_default_margin(SIDE_TOP, 4 * scale); + cbx_focus->set_default_margin(SIDE_BOTTOM, 4 * scale); theme->set_stylebox("normal", "CheckBox", cbx_empty); theme->set_stylebox("pressed", "CheckBox", cbx_empty); @@ -299,29 +348,35 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("focus", "CheckBox", cbx_focus); theme->set_icon("checked", "CheckBox", make_icon(checked_png)); + theme->set_icon("checked_disabled", "CheckBox", make_icon(checked_disabled_png)); theme->set_icon("unchecked", "CheckBox", make_icon(unchecked_png)); + theme->set_icon("unchecked_disabled", "CheckBox", make_icon(unchecked_disabled_png)); theme->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png)); + theme->set_icon("radio_checked_disabled", "CheckBox", make_icon(radio_checked_disabled_png)); theme->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png)); + theme->set_icon("radio_unchecked_disabled", "CheckBox", make_icon(radio_unchecked_disabled_png)); theme->set_font("font", "CheckBox", Ref<Font>()); theme->set_font_size("font_size", "CheckBox", -1); theme->set_color("font_color", "CheckBox", control_font_color); - theme->set_color("font_color_pressed", "CheckBox", control_font_color_pressed); - theme->set_color("font_color_hover", "CheckBox", control_font_color_hover); - theme->set_color("font_color_hover_pressed", "CheckBox", control_font_color_pressed); - theme->set_color("font_color_disabled", "CheckBox", control_font_color_disabled); + theme->set_color("font_pressed_color", "CheckBox", control_font_pressed_color); + theme->set_color("font_hover_color", "CheckBox", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckBox", control_font_pressed_color); + theme->set_color("font_disabled_color", "CheckBox", control_font_disabled_color); + theme->set_color("font_outline_color", "CheckBox", Color(1, 1, 1)); theme->set_constant("hseparation", "CheckBox", 4 * scale); theme->set_constant("check_vadjust", "CheckBox", 0 * scale); + theme->set_constant("outline_size", "CheckBox", 0); // CheckButton Ref<StyleBox> cb_empty = memnew(StyleBoxEmpty); - cb_empty->set_default_margin(MARGIN_LEFT, 6 * scale); - cb_empty->set_default_margin(MARGIN_RIGHT, 6 * scale); - cb_empty->set_default_margin(MARGIN_TOP, 4 * scale); - cb_empty->set_default_margin(MARGIN_BOTTOM, 4 * scale); + cb_empty->set_default_margin(SIDE_LEFT, 6 * scale); + cb_empty->set_default_margin(SIDE_RIGHT, 6 * scale); + cb_empty->set_default_margin(SIDE_TOP, 4 * scale); + cb_empty->set_default_margin(SIDE_BOTTOM, 4 * scale); theme->set_stylebox("normal", "CheckButton", cb_empty); theme->set_stylebox("pressed", "CheckButton", cb_empty); @@ -344,13 +399,15 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "CheckButton", -1); theme->set_color("font_color", "CheckButton", control_font_color); - theme->set_color("font_color_pressed", "CheckButton", control_font_color_pressed); - theme->set_color("font_color_hover", "CheckButton", control_font_color_hover); - theme->set_color("font_color_hover_pressed", "CheckButton", control_font_color_pressed); - theme->set_color("font_color_disabled", "CheckButton", control_font_color_disabled); + theme->set_color("font_pressed_color", "CheckButton", control_font_pressed_color); + theme->set_color("font_hover_color", "CheckButton", control_font_hover_color); + theme->set_color("font_hover_pressed_color", "CheckButton", control_font_pressed_color); + theme->set_color("font_disabled_color", "CheckButton", control_font_disabled_color); + theme->set_color("font_outline_color", "CheckButton", Color(1, 1, 1)); theme->set_constant("hseparation", "CheckButton", 4 * scale); theme->set_constant("check_vadjust", "CheckButton", 0 * scale); + theme->set_constant("outline_size", "CheckButton", 0); // Label @@ -359,12 +416,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "Label", -1); theme->set_color("font_color", "Label", Color(1, 1, 1)); - theme->set_color("font_color_shadow", "Label", Color(0, 0, 0, 0)); - theme->set_color("font_outline_modulate", "Label", Color(1, 1, 1)); + theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0)); + theme->set_color("font_outline_color", "Label", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "Label", 1 * scale); theme->set_constant("shadow_offset_y", "Label", 1 * scale); - theme->set_constant("outline_size", "Label", 0 * scale); + theme->set_constant("outline_size", "Label", 0); theme->set_constant("shadow_outline_size", "Label", 1 * scale); theme->set_constant("line_spacing", "Label", 3 * scale); @@ -378,14 +435,16 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "LineEdit", -1); theme->set_color("font_color", "LineEdit", control_font_color); - theme->set_color("font_color_selected", "LineEdit", Color(0, 0, 0)); - theme->set_color("font_color_uneditable", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); - theme->set_color("cursor_color", "LineEdit", control_font_color_hover); - theme->set_color("selection_color", "LineEdit", font_color_selection); + theme->set_color("font_selected_color", "LineEdit", Color(0, 0, 0)); + theme->set_color("font_uneditable_color", "LineEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "LineEdit", Color(1, 1, 1)); + theme->set_color("cursor_color", "LineEdit", control_font_hover_color); + theme->set_color("selection_color", "LineEdit", control_selection_color); theme->set_color("clear_button_color", "LineEdit", control_font_color); - theme->set_color("clear_button_color_pressed", "LineEdit", control_font_color_pressed); + theme->set_color("clear_button_color_pressed", "LineEdit", control_font_pressed_color); - theme->set_constant("minimum_spaces", "LineEdit", 12 * scale); + theme->set_constant("minimum_character_width", "LineEdit", 4); + theme->set_constant("outline_size", "LineEdit", 0); theme->set_icon("clear", "LineEdit", make_icon(line_edit_clear_png)); @@ -397,8 +456,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("font", "ProgressBar", Ref<Font>()); theme->set_font_size("font_size", "ProgressBar", -1); - theme->set_color("font_color", "ProgressBar", control_font_color_hover); - theme->set_color("font_color_shadow", "ProgressBar", Color(0, 0, 0)); + theme->set_color("font_color", "ProgressBar", control_font_hover_color); + theme->set_color("font_shadow_color", "ProgressBar", Color(0, 0, 0)); + theme->set_color("font_outline_color", "ProgressBar", Color(1, 1, 1)); + + theme->set_constant("outline_size", "ProgressBar", 0); // TextEdit @@ -417,12 +479,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_color("completion_background_color", "TextEdit", Color(0.17, 0.16, 0.2)); theme->set_color("completion_selected_color", "TextEdit", Color(0.26, 0.26, 0.27)); theme->set_color("completion_existing_color", "TextEdit", Color(0.87, 0.87, 0.87, 0.13)); - theme->set_color("completion_scroll_color", "TextEdit", control_font_color_pressed); + theme->set_color("completion_scroll_color", "TextEdit", control_font_pressed_color); theme->set_color("completion_font_color", "TextEdit", Color(0.67, 0.67, 0.67)); theme->set_color("font_color", "TextEdit", control_font_color); - theme->set_color("font_color_selected", "TextEdit", Color(0, 0, 0)); - 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("font_selected_color", "TextEdit", Color(0, 0, 0)); + theme->set_color("font_readonly_color", "TextEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "TextEdit", Color(1, 1, 1)); + theme->set_color("selection_color", "TextEdit", control_selection_color); theme->set_color("mark_color", "TextEdit", Color(1.0, 0.4, 0.4, 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)); @@ -435,8 +498,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("completion_max_width", "TextEdit", 50); theme->set_constant("completion_scroll_width", "TextEdit", 3); theme->set_constant("line_spacing", "TextEdit", 4 * scale); + theme->set_constant("outline_size", "TextEdit", 0); // 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)); @@ -457,12 +522,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const 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_scroll_color", "CodeEdit", control_font_pressed_color); 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("font_selected_color", "CodeEdit", Color(0, 0, 0)); + theme->set_color("font_readonly_color", "CodeEdit", Color(control_font_color.r, control_font_color.g, control_font_color.b, 0.5f)); + theme->set_color("font_outline_color", "CodeEdit", Color(1, 1, 1)); + theme->set_color("selection_color", "CodeEdit", control_selection_color); 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)); @@ -480,6 +546,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("completion_max_width", "CodeEdit", 50); theme->set_constant("completion_scroll_width", "CodeEdit", 3); theme->set_constant("line_spacing", "CodeEdit", 4 * scale); + theme->set_constant("outline_size", "CodeEdit", 0); Ref<Texture2D> empty_icon = memnew(ImageTexture); @@ -535,7 +602,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png)); - //scroll container + // ScrollContainer + Ref<StyleBoxEmpty> empty; empty.instance(); theme->set_stylebox("bg", "ScrollContainer", empty); @@ -547,7 +615,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("scaleborder_size", "Window", 4 * scale); theme->set_font("title_font", "Window", large_font); + theme->set_font_size("title_font_size", "Window", -1); + theme->set_color("title_color", "Window", Color(0, 0, 0)); + theme->set_color("title_outline_modulate", "Window", Color(1, 1, 1)); + + theme->set_constant("title_outline_size", "Window", 0); theme->set_constant("title_height", "Window", 20 * scale); theme->set_constant("resize_margin", "Window", 4 * scale); @@ -559,6 +632,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const // File Dialog theme->set_icon("parent_folder", "FileDialog", make_icon(icon_parent_folder_png)); + theme->set_icon("back_folder", "FileDialog", make_icon(arrow_left_png)); + theme->set_icon("forward_folder", "FileDialog", make_icon(arrow_right_png)); theme->set_icon("reload", "FileDialog", make_icon(icon_reload_png)); theme->set_icon("toggle_hidden", "FileDialog", make_icon(icon_visibility_png)); @@ -568,7 +643,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> selected = make_stylebox(selection_png, 6, 6, 6, 6); for (int i = 0; i < 4; i++) { - selected->set_expand_margin_size(Margin(i), 2 * scale); + selected->set_expand_margin_size(Side(i), 2 * scale); } theme->set_stylebox("panel", "PopupPanel", style_pp); @@ -598,13 +673,17 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "PopupMenu", -1); theme->set_color("font_color", "PopupMenu", control_font_color); - theme->set_color("font_color_accel", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8)); - theme->set_color("font_color_disabled", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); - theme->set_color("font_color_hover", "PopupMenu", control_font_color); - theme->set_color("font_color_separator", "PopupMenu", control_font_color); + theme->set_color("font_accelerator_color", "PopupMenu", Color(0.7, 0.7, 0.7, 0.8)); + theme->set_color("font_disabled_color", "PopupMenu", Color(0.4, 0.4, 0.4, 0.8)); + theme->set_color("font_hover_color", "PopupMenu", control_font_color); + theme->set_color("font_separator_color", "PopupMenu", control_font_color); + theme->set_color("font_outline_color", "PopupMenu", Color(1, 1, 1)); theme->set_constant("hseparation", "PopupMenu", 4 * scale); theme->set_constant("vseparation", "PopupMenu", 4 * scale); + theme->set_constant("outline_size", "PopupMenu", 0); + theme->set_constant("item_start_padding", "PopupMenu", 2 * scale); + theme->set_constant("item_end_padding", "PopupMenu", 2 * scale); // GraphNode @@ -617,8 +696,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> graph_bpoint = make_stylebox(graph_node_breakpoint_png, 6, 24, 6, 5, 16, 24, 16, 6); Ref<StyleBoxTexture> graph_position = make_stylebox(graph_node_position_png, 6, 24, 6, 5, 16, 24, 16, 6); - //graphsb->set_expand_margin_size(MARGIN_LEFT,10); - //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); + //graphsb->set_expand_margin_size(SIDE_LEFT,10); + //graphsb->set_expand_margin_size(SIDE_RIGHT,10); theme->set_stylebox("frame", "GraphNode", graphsb); theme->set_stylebox("selectedframe", "GraphNode", graphsbselected); theme->set_stylebox("defaultframe", "GraphNode", graphsbdefault); @@ -671,12 +750,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "Tree", -1); theme->set_color("title_button_color", "Tree", control_font_color); - theme->set_color("font_color", "Tree", control_font_color_low); - theme->set_color("font_color_selected", "Tree", control_font_color_pressed); + theme->set_color("font_color", "Tree", control_font_low_color); + theme->set_color("font_selected_color", "Tree", control_font_pressed_color); + theme->set_color("font_outline_color", "Tree", Color(1, 1, 1)); theme->set_color("guide_color", "Tree", Color(0, 0, 0, 0.1)); theme->set_color("drop_position_color", "Tree", Color(1, 0.3, 0.2)); theme->set_color("relationship_line_color", "Tree", Color(0.27, 0.27, 0.27)); - theme->set_color("custom_button_font_highlight", "Tree", control_font_color_hover); + theme->set_color("custom_button_font_highlight", "Tree", control_font_hover_color); theme->set_constant("hseparation", "Tree", 4 * scale); theme->set_constant("vseparation", "Tree", 4 * scale); @@ -686,8 +766,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("draw_guides", "Tree", 1); theme->set_constant("scroll_border", "Tree", 4); theme->set_constant("scroll_speed", "Tree", 12); + theme->set_constant("outline_size", "Tree", 0); // ItemList + Ref<StyleBoxTexture> item_selected = make_stylebox(selection_png, 4, 4, 4, 4, 8, 2, 8, 2); Ref<StyleBoxTexture> item_selected_oof = make_stylebox(selection_oof_png, 4, 4, 4, 4, 8, 2, 8, 2); @@ -701,23 +783,26 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("font", "ItemList", Ref<Font>()); theme->set_font_size("font_size", "ItemList", -1); - theme->set_color("font_color", "ItemList", control_font_color_lower); - theme->set_color("font_color_selected", "ItemList", control_font_color_pressed); + theme->set_color("font_color", "ItemList", control_font_lower_color); + theme->set_color("font_selected_color", "ItemList", control_font_pressed_color); + theme->set_color("font_outline_color", "ItemList", Color(1, 1, 1)); theme->set_color("guide_color", "ItemList", Color(0, 0, 0, 0.1)); theme->set_stylebox("selected", "ItemList", item_selected_oof); theme->set_stylebox("selected_focus", "ItemList", item_selected); theme->set_stylebox("cursor", "ItemList", focus); theme->set_stylebox("cursor_unfocused", "ItemList", focus); + theme->set_constant("outline_size", "ItemList", 0); + // TabContainer Ref<StyleBoxTexture> tc_sb = sb_expand(make_stylebox(tab_container_bg_png, 4, 4, 4, 4, 4, 4, 4, 4), 3, 3, 3, 3); - tc_sb->set_expand_margin_size(MARGIN_TOP, 2 * scale); - tc_sb->set_default_margin(MARGIN_TOP, 8 * scale); + tc_sb->set_expand_margin_size(SIDE_TOP, 2 * scale); + tc_sb->set_default_margin(SIDE_TOP, 8 * scale); - theme->set_stylebox("tab_fg", "TabContainer", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); - theme->set_stylebox("tab_bg", "TabContainer", sb_expand(make_stylebox(tab_behind_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); + theme->set_stylebox("tab_selected", "TabContainer", sb_expand(make_stylebox(tab_current_png, 4, 4, 4, 1, 16, 4, 16, 4), 2, 2, 2, 2)); + theme->set_stylebox("tab_unselected", "TabContainer", sb_expand(make_stylebox(tab_behind_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); theme->set_stylebox("tab_disabled", "TabContainer", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); theme->set_stylebox("panel", "TabContainer", tc_sb); @@ -731,17 +816,19 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("font", "TabContainer", Ref<Font>()); theme->set_font_size("font_size", "TabContainer", -1); - theme->set_color("font_color_fg", "TabContainer", control_font_color_hover); - theme->set_color("font_color_bg", "TabContainer", control_font_color_low); - theme->set_color("font_color_disabled", "TabContainer", control_font_color_disabled); + theme->set_color("font_selected_color", "TabContainer", control_font_hover_color); + theme->set_color("font_unselected_color", "TabContainer", control_font_low_color); + theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color); + theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1)); theme->set_constant("side_margin", "TabContainer", 8 * scale); theme->set_constant("icon_separation", "TabContainer", 4 * scale); + theme->set_constant("outline_size", "TabContainer", 0); // Tabs - theme->set_stylebox("tab_fg", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2)); - theme->set_stylebox("tab_bg", "Tabs", sb_expand(make_stylebox(tab_behind_png, 5, 4, 5, 1, 16, 5, 16, 2), 3, 3, 3, 3)); + theme->set_stylebox("tab_selected", "Tabs", sb_expand(make_stylebox(tab_current_png, 4, 3, 4, 1, 16, 3, 16, 2), 2, 2, 2, 2)); + theme->set_stylebox("tab_unselected", "Tabs", sb_expand(make_stylebox(tab_behind_png, 5, 4, 5, 1, 16, 5, 16, 2), 3, 3, 3, 3)); theme->set_stylebox("tab_disabled", "Tabs", sb_expand(make_stylebox(tab_disabled_png, 5, 5, 5, 1, 16, 6, 16, 4), 3, 0, 3, 3)); theme->set_stylebox("panel", "Tabs", tc_sb); theme->set_stylebox("button_pressed", "Tabs", make_stylebox(button_pressed_png, 4, 4, 4, 4)); @@ -756,11 +843,13 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font("font", "Tabs", Ref<Font>()); theme->set_font_size("font_size", "Tabs", -1); - theme->set_color("font_color_fg", "Tabs", control_font_color_hover); - theme->set_color("font_color_bg", "Tabs", control_font_color_low); - theme->set_color("font_color_disabled", "Tabs", control_font_color_disabled); + theme->set_color("font_selected_color", "Tabs", control_font_hover_color); + theme->set_color("font_unselected_color", "Tabs", control_font_low_color); + theme->set_color("font_disabled_color", "Tabs", control_font_disabled_color); + theme->set_color("font_outline_color", "Tabs", Color(1, 1, 1)); theme->set_constant("hseparation", "Tabs", 4 * scale); + theme->set_constant("outline_size", "Tabs", 0); // Separators @@ -801,6 +890,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_icon("color_sample", "ColorPicker", make_icon(color_picker_sample_png)); theme->set_icon("preset_bg", "ColorPicker", make_icon(mini_checkerboard_png)); theme->set_icon("overbright_indicator", "ColorPicker", make_icon(overbright_indicator_png)); + theme->set_icon("bar_arrow", "ColorPicker", make_icon(bar_arrow_png)); theme->set_icon("bg", "ColorPickerButton", make_icon(mini_checkerboard_png)); @@ -808,7 +898,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<StyleBoxTexture> style_tt = make_stylebox(tooltip_bg_png, 4, 4, 4, 4); for (int i = 0; i < 4; i++) { - style_tt->set_expand_margin_size((Margin)i, 4 * scale); + style_tt->set_expand_margin_size((Side)i, 4 * scale); } theme->set_stylebox("panel", "TooltipPanel", style_tt); @@ -817,10 +907,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("font_size", "TooltipLabel", -1); theme->set_color("font_color", "TooltipLabel", Color(0, 0, 0)); - theme->set_color("font_color_shadow", "TooltipLabel", Color(0, 0, 0, 0.1)); + theme->set_color("font_shadow_color", "TooltipLabel", Color(0, 0, 0, 0.1)); + theme->set_color("font_outline_color", "TooltipLabel", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "TooltipLabel", 1); theme->set_constant("shadow_offset_y", "TooltipLabel", 1); + theme->set_constant("outline_size", "TooltipLabel", 0); // RichTextLabel @@ -840,10 +932,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_font_size("mono_font_size", "RichTextLabel", -1); theme->set_color("default_color", "RichTextLabel", Color(1, 1, 1)); - theme->set_color("font_color_selected", "RichTextLabel", font_color_selection); + theme->set_color("font_selected_color", "RichTextLabel", Color(0, 0, 0)); theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8)); - theme->set_color("font_color_shadow", "RichTextLabel", Color(0, 0, 0, 0)); + theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0)); + + theme->set_color("font_outline_color", "RichTextLabel", Color(1, 1, 1)); theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale); theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale); @@ -853,9 +947,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale); theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale); + theme->set_constant("outline_size", "RichTextLabel", 0); + theme->set_color("table_odd_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); theme->set_color("table_even_row_bg", "RichTextLabel", Color(0, 0, 0, 0)); theme->set_color("table_border", "RichTextLabel", Color(0, 0, 0, 0)); + // Containers theme->set_stylebox("bg", "VSplitContainer", make_stylebox(vsplit_bg_png, 1, 1, 1, 1)); @@ -895,6 +992,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("bezier_len_neg", "GraphEdit", 160 * scale); // Visual Node Ports + theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale); theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale); @@ -926,45 +1024,15 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) { Ref<StyleBox> default_style; Ref<Texture2D> default_icon; Ref<Font> default_font; - int default_font_size = 16; + int default_font_size = 14; if (p_font.is_valid()) { default_font = p_font; } else if (p_hidpi) { - TextServer::BitmapFontData data; - data.height = _hidpi_font_height; - data.ascent = _hidpi_font_ascent; - data.charcount = _hidpi_font_charcount; - data.char_rects = &_hidpi_font_charrects[0][0]; - data.kerning_count = _hidpi_font_kerning_pair_count; - data.kernings = &_hidpi_font_kerning_pairs[0][0]; - data.w = _hidpi_font_img_width; - data.h = _hidpi_font_img_height; - data.img = _hidpi_font_img_data; - - Ref<FontData> font_data; - font_data.instance(); - font_data->load_memory((const uint8_t *)&data, sizeof(data), "fnt"); - default_font_size = font_data->get_base_size(); - + Ref<FontData> font_data = make_font(_hidpi_font_height, _hidpi_font_ascent, _hidpi_font_charcount, &_hidpi_font_charrects[0][0], _hidpi_font_kerning_pair_count, &_hidpi_font_kerning_pairs[0][0], _hidpi_font_img_width, _hidpi_font_img_height, _hidpi_font_img_data); default_font.instance(); default_font->add_data(font_data); } else { - TextServer::BitmapFontData data; - data.height = _lodpi_font_height; - data.ascent = _lodpi_font_ascent; - data.charcount = _lodpi_font_charcount; - data.char_rects = &_lodpi_font_charrects[0][0]; - data.kerning_count = _lodpi_font_kerning_pair_count; - data.kernings = &_lodpi_font_kerning_pairs[0][0]; - data.w = _lodpi_font_img_width; - data.h = _lodpi_font_img_height; - data.img = _lodpi_font_img_data; - - Ref<FontData> font_data; - font_data.instance(); - font_data->load_memory((const uint8_t *)&data, sizeof(data), "fnt"); - default_font_size = font_data->get_base_size(); - + Ref<FontData> font_data = make_font(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data); default_font.instance(); default_font->add_data(font_data); } diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h index 46f89a9b50..a7b2bec5a4 100644 --- a/scene/resources/default_theme/default_theme.h +++ b/scene/resources/default_theme/default_theme.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/default_theme/radio_checked_disabled.png b/scene/resources/default_theme/radio_checked_disabled.png Binary files differnew file mode 100644 index 0000000000..72f08ecb96 --- /dev/null +++ b/scene/resources/default_theme/radio_checked_disabled.png diff --git a/scene/resources/default_theme/radio_unchecked_disabled.png b/scene/resources/default_theme/radio_unchecked_disabled.png Binary files differnew file mode 100644 index 0000000000..a8f4c1b555 --- /dev/null +++ b/scene/resources/default_theme/radio_unchecked_disabled.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index b905c9db69..5d4dbd0758 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -14,6 +14,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 bar_arrow_png[] = { + 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x14, 0x8, 0x4, 0x0, 0x0, 0x0, 0x2e, 0x6b, 0x75, 0xfc, 0x0, 0x0, 0x0, 0x4, 0x67, 0x41, 0x4d, 0x41, 0x0, 0x0, 0xb1, 0x8f, 0xb, 0xfc, 0x61, 0x5, 0x0, 0x0, 0x0, 0x1, 0x73, 0x52, 0x47, 0x42, 0x0, 0xae, 0xce, 0x1c, 0xe9, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0xe, 0xc0, 0x1, 0x6a, 0xd6, 0x89, 0x9, 0x0, 0x0, 0x0, 0x65, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0x63, 0xfc, 0xcf, 0x80, 0x1f, 0x30, 0x8e, 0x20, 0x5, 0x8c, 0x38, 0x24, 0xff, 0x53, 0x5f, 0xc1, 0xb, 0xee, 0x9f, 0x53, 0x18, 0x18, 0xd8, 0x73, 0x24, 0xbe, 0x62, 0x55, 0x70, 0x5f, 0x83, 0x61, 0x15, 0xa3, 0x2e, 0x3, 0x3, 0xc3, 0xd, 0xe6, 0x30, 0xd9, 0xcb, 0x18, 0xa, 0x1e, 0xc6, 0xfd, 0x9f, 0xc6, 0xc0, 0xd, 0x35, 0xea, 0x3b, 0x63, 0x81, 0xfc, 0x2c, 0x14, 0x5, 0xf, 0x2a, 0x18, 0xda, 0xd1, 0x1c, 0x50, 0xa9, 0xd0, 0x1, 0x57, 0xf0, 0x10, 0x53, 0x9a, 0x81, 0x81, 0x81, 0xa1, 0x52, 0xbe, 0x83, 0x81, 0x81, 0xf1, 0x3f, 0x2e, 0x69, 0xa8, 0x12, 0x3a, 0x4, 0x14, 0x0, 0x7b, 0xda, 0x34, 0x1, 0xbb, 0xb5, 0x3e, 0x6c, 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 }; @@ -42,6 +46,10 @@ static const unsigned char checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x8d, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x58, 0x56, 0x63, 0xb0, 0xaf, 0xb5, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0xb6, 0xb6, 0xb9, 0x57, 0x57, 0x5a, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x8b, 0x8b, 0x8d, 0xff, 0xff, 0xff, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x42, 0x42, 0x47, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0x25, 0x25, 0x2a, 0x4e, 0x4e, 0x52, 0x26, 0x26, 0x2b, 0xc5, 0xc5, 0xc7, 0xaa, 0xaa, 0xab, 0xb8, 0xb8, 0xba, 0x5f, 0x5f, 0x63, 0x74, 0x74, 0x77, 0xed, 0xed, 0xed, 0x33, 0x33, 0x38, 0x8d, 0x8d, 0x8f, 0xb8, 0xb8, 0xb9, 0x35, 0x35, 0x39, 0x3a, 0x3a, 0x3e, 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xfa, 0xb2, 0xb2, 0xb4, 0x45, 0x45, 0x49, 0x61, 0x61, 0x65, 0x8f, 0x8f, 0x92, 0x63, 0x63, 0x66, 0x2a, 0x2a, 0x2f, 0x40, 0x82, 0xb, 0xf6, 0x0, 0x0, 0x0, 0xf, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xfa, 0xdd, 0xfb, 0xfb, 0xb4, 0xfa, 0xb8, 0xf0, 0x7f, 0x59, 0x0, 0x0, 0x0, 0x7e, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x5d, 0xca, 0x5, 0xb2, 0x2, 0x30, 0x18, 0x3, 0xe1, 0x4d, 0xed, 0xb9, 0x60, 0xf7, 0x3f, 0x20, 0xee, 0x4e, 0x99, 0xe0, 0xb0, 0x63, 0xfd, 0xbf, 0x86, 0xd7, 0x12, 0x72, 0x38, 0x69, 0x5b, 0x6b, 0x42, 0x45, 0xe5, 0xa, 0xab, 0x95, 0x41, 0x9f, 0x32, 0x20, 0x69, 0x2d, 0xbc, 0x50, 0x46, 0x3a, 0x10, 0x17, 0x5f, 0x49, 0x4, 0x7f, 0x90, 0x57, 0x89, 0xb7, 0xc5, 0x5f, 0x96, 0x17, 0x2e, 0x93, 0xcb, 0x8e, 0x3a, 0x83, 0xb, 0xc4, 0x8e, 0xd4, 0xff, 0x5c, 0x73, 0x83, 0x69, 0x9e, 0x95, 0xfc, 0x3b, 0xf4, 0x33, 0xe0, 0xf8, 0x61, 0xd3, 0xf1, 0x7d, 0x5d, 0x30, 0x7a, 0x6f, 0x89, 0xb, 0xd4, 0x5a, 0xe1, 0x40, 0xf, 0xfc, 0x34, 0x6c, 0xd2, 0x56, 0x80, 0xef, 0xfd, 0x9, 0xd2, 0x3a, 0x5e, 0x41, 0x15, 0x21, 0x77, 0x6, 0xc7, 0x6b, 0x47, 0x4e, 0x3a, 0x2f, 0x53, 0xb4, 0x10, 0xc7, 0x8c, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x99, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x73, 0x72, 0x7b, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x82, 0x80, 0x8a, 0x90, 0x90, 0x93, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x93, 0x93, 0x95, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x7d, 0x7d, 0x7f, 0x58, 0x58, 0x5b, 0xa4, 0xa4, 0xa4, 0x9e, 0x9e, 0xa0, 0x9e, 0x9e, 0x9e, 0x9b, 0x9b, 0x9c, 0x9b, 0x9b, 0x9b, 0x9a, 0x9a, 0x9a, 0x99, 0x99, 0x99, 0x98, 0x98, 0x98, 0x97, 0x97, 0x97, 0x96, 0x96, 0x96, 0x95, 0x95, 0x95, 0x93, 0x93, 0x94, 0x8f, 0x8f, 0x8f, 0x86, 0x86, 0x88, 0x85, 0x85, 0x86, 0x82, 0x82, 0x83, 0x81, 0x81, 0x83, 0x7f, 0x7f, 0x81, 0x7c, 0x7c, 0x7e, 0x7a, 0x7a, 0x7d, 0x78, 0x78, 0x7b, 0x71, 0x71, 0x74, 0x68, 0x68, 0x6c, 0x66, 0x66, 0x6a, 0x65, 0x65, 0x68, 0x63, 0x63, 0x66, 0x5f, 0x5f, 0x63, 0x5c, 0x5c, 0x60, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x59, 0x59, 0x5c, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x10, 0x13, 0xbb, 0xf, 0x0, 0x0, 0x0, 0x10, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x27, 0x50, 0x66, 0x68, 0x6a, 0x81, 0xb4, 0xb4, 0xdd, 0xfa, 0xfa, 0xfb, 0xfb, 0x5b, 0xd1, 0xf1, 0xe6, 0x0, 0x0, 0x0, 0x96, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x5d, 0x8f, 0xc9, 0x12, 0x82, 0x30, 0x14, 0x4, 0x87, 0x18, 0x50, 0x51, 0x44, 0x25, 0x42, 0x4, 0x77, 0xc4, 0x8d, 0x97, 0x0, 0xf9, 0xff, 0x8f, 0xb3, 0x88, 0xa4, 0x4a, 0xed, 0x63, 0x5f, 0xa6, 0x7, 0xf8, 0x7, 0x1e, 0xe3, 0x7e, 0x60, 0x19, 0x4f, 0x46, 0x1e, 0x0, 0x36, 0x8d, 0x4c, 0x67, 0x59, 0x65, 0x33, 0x6, 0x80, 0x47, 0xad, 0x56, 0x3d, 0xb7, 0x3c, 0x5d, 0x70, 0x0, 0xbe, 0xd1, 0x44, 0x65, 0x4d, 0x94, 0xc8, 0xc2, 0xf8, 0x0, 0x82, 0x4e, 0x91, 0x94, 0x15, 0x5d, 0xd2, 0xec, 0xde, 0x5, 0x83, 0x38, 0xc8, 0xe3, 0x63, 0x23, 0xce, 0xca, 0x9, 0x7a, 0x6e, 0xf3, 0x93, 0x48, 0x1a, 0x27, 0x14, 0x35, 0x3b, 0xb9, 0x5e, 0x56, 0xe4, 0x84, 0x22, 0xba, 0xa, 0x51, 0xd0, 0xb7, 0xa8, 0xcb, 0xfd, 0xcb, 0x9, 0x3b, 0xfb, 0x41, 0xdb, 0x59, 0x17, 0xa6, 0x94, 0x6e, 0xe3, 0x3e, 0x8c, 0x85, 0xf1, 0x90, 0x6e, 0xe6, 0x21, 0xfb, 0x39, 0xe7, 0x73, 0xe6, 0xfd, 0x5f, 0x7, 0xde, 0xc3, 0xb5, 0x16, 0x87, 0xb0, 0x9e, 0x42, 0x46, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char checker_bg_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0xe1, 0x64, 0xe1, 0x57, 0x0, 0x0, 0x0, 0x14, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0xfc, 0xcf, 0xc0, 0xc0, 0xd0, 0x0, 0xc4, 0xf8, 0x18, 0xf5, 0x84, 0x19, 0x0, 0x9f, 0x5f, 0xa, 0x1, 0xf8, 0xef, 0x65, 0xf4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -282,10 +290,18 @@ static const unsigned char radio_checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x42, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0xd1, 0xa7, 0xf5, 0xaa, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x63, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x6d, 0x4f, 0x55, 0x2, 0x43, 0x31, 0x8, 0x4b, 0xe8, 0x6a, 0xf7, 0xbf, 0xeb, 0xc, 0x9b, 0x6b, 0x1f, 0x9f, 0xc4, 0x89, 0xbf, 0xbb, 0x3f, 0x2a, 0x49, 0x64, 0xa6, 0x3e, 0x1e, 0x1c, 0x7c, 0x3e, 0xf2, 0x14, 0xb7, 0xc7, 0xac, 0xf1, 0x10, 0xa6, 0xe8, 0x1, 0x44, 0xad, 0x42, 0xb9, 0x33, 0x22, 0x43, 0x95, 0x68, 0x55, 0xa4, 0xdc, 0x1f, 0x1e, 0xa1, 0x67, 0xa2, 0x57, 0x96, 0x22, 0x0, 0xc2, 0x3d, 0xf5, 0x44, 0x8c, 0x8a, 0x5d, 0x21, 0x80, 0x74, 0x83, 0x1e, 0x97, 0xc7, 0x22, 0x59, 0x4c, 0xd7, 0xd8, 0xb5, 0x18, 0x4a, 0x7b, 0x57, 0x57, 0xdb, 0x1a, 0xf7, 0x77, 0x17, 0x3a, 0x56, 0x4e, 0x11, 0x6f, 0x82, 0x20, 0xde, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char radio_checked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd8, 0xd8, 0xd8, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0xd3, 0xd3, 0xd3, 0xa2, 0xa2, 0xa2, 0x79, 0x79, 0x79, 0x73, 0x73, 0x73, 0x1c, 0x1c, 0x1c, 0x3, 0x3, 0x3, 0x0, 0x0, 0x0, 0x83, 0xac, 0xe9, 0xaf, 0x0, 0x0, 0x0, 0x1, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x40, 0xe6, 0xd8, 0x66, 0x0, 0x0, 0x0, 0x3f, 0x49, 0x44, 0x41, 0x54, 0x18, 0xd3, 0x63, 0x60, 0x20, 0xe, 0xf0, 0x8, 0x2, 0x1, 0xf, 0x9c, 0x2b, 0x2c, 0x8, 0x5, 0xc2, 0x50, 0x1, 0xb0, 0x34, 0x58, 0x11, 0x5c, 0xbd, 0x10, 0x3f, 0x10, 0x8, 0xc1, 0x74, 0x1, 0x65, 0xf8, 0xc1, 0x0, 0xa6, 0x4, 0x28, 0x1, 0x11, 0xe0, 0xc1, 0x2d, 0x80, 0xa6, 0x5, 0xc3, 0x50, 0xc, 0x6b, 0x31, 0x1d, 0x86, 0xe1, 0x74, 0xfc, 0x0, 0x0, 0x1b, 0xc, 0x7, 0xb9, 0xa, 0x5e, 0x2e, 0x12, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char radio_unchecked_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x2a, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4, 0x3, 0x4, 0x9, 0x9, 0x9, 0x6, 0x6, 0x6, 0xa, 0xa, 0xb, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x27, 0x7f, 0x7f, 0x82, 0xd9, 0xd9, 0xd9, 0x47, 0x47, 0x48, 0x2b, 0x6e, 0xf2, 0xbf, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1b, 0x88, 0xd1, 0xf7, 0x64, 0xf6, 0x2, 0xb3, 0xed, 0xd7, 0x0, 0x0, 0x0, 0x49, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x63, 0x40, 0x2, 0x61, 0x15, 0xed, 0xa9, 0x20, 0x5a, 0x72, 0xf5, 0x99, 0x33, 0xbb, 0x26, 0x1, 0x19, 0x73, 0xcf, 0x0, 0xc1, 0x4d, 0x6, 0x6, 0xd6, 0x35, 0x20, 0xc6, 0xa9, 0x0, 0x6, 0xb6, 0x3d, 0x20, 0xc6, 0xe9, 0x4, 0x6, 0xf6, 0x33, 0x60, 0x50, 0xc0, 0xc0, 0x1, 0x61, 0x34, 0xc0, 0x19, 0x70, 0x29, 0xb8, 0x62, 0xb8, 0x76, 0x84, 0x81, 0xc, 0x96, 0x20, 0x2b, 0xa6, 0xc0, 0x2d, 0x45, 0x0, 0x0, 0x37, 0xca, 0x3d, 0x81, 0xb4, 0x84, 0xb6, 0x80, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char radio_unchecked_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, 0x4, 0x3, 0x0, 0x0, 0x0, 0xed, 0xdd, 0xe2, 0x52, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0xf, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x54, 0x54, 0x54, 0xad, 0xad, 0xad, 0x80, 0x80, 0x81, 0x64, 0x64, 0x64, 0xf4, 0x17, 0x36, 0x28, 0x0, 0x0, 0x0, 0x2, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x1b, 0xfc, 0xf6, 0x4, 0xd4, 0x0, 0x0, 0x0, 0x40, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0x7d, 0x8d, 0xb1, 0x11, 0x80, 0x40, 0xc, 0xc3, 0x94, 0xd, 0x12, 0x60, 0x1, 0xc4, 0x4, 0xb0, 0x1, 0xfb, 0x2f, 0x45, 0xe5, 0x3b, 0xaa, 0x57, 0xe5, 0xc2, 0xb6, 0x20, 0xc0, 0xcc, 0xc, 0x40, 0xed, 0x7a, 0x37, 0x70, 0xa8, 0xbe, 0x50, 0x9b, 0xea, 0xd9, 0xd4, 0xa3, 0x7a, 0x35, 0xa5, 0xaa, 0xeb, 0x90, 0x72, 0xe6, 0x39, 0xfc, 0x2b, 0x22, 0xd, 0x1f, 0xe7, 0x64, 0xa, 0x5d, 0x6c, 0xfe, 0xc1, 0x3b, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char scroll_bg_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, 0x3, 0x0, 0x0, 0x0, 0x61, 0xab, 0xac, 0xd5, 0x0, 0x0, 0x0, 0x45, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x40, 0x3e, 0x4a, 0x2a, 0x29, 0x2f, 0x20, 0x20, 0x24, 0x3f, 0x3e, 0x49, 0x1f, 0x1f, 0x24, 0x20, 0x20, 0x24, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x3f, 0x3e, 0x49, 0x3f, 0x3e, 0x49, 0x1e, 0x1e, 0x23, 0x20, 0x20, 0x25, 0x22, 0x22, 0x27, 0x23, 0x23, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x14, 0xee, 0x69, 0x20, 0x0, 0x0, 0x0, 0x11, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x4, 0x19, 0x40, 0x5d, 0x66, 0x28, 0x93, 0xf0, 0xfc, 0x94, 0xfc, 0xfd, 0x67, 0x1a, 0x96, 0x95, 0x1c, 0xf0, 0x43, 0x52, 0x0, 0x0, 0x0, 0x55, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x55, 0x8e, 0x45, 0x2, 0x80, 0x50, 0x10, 0x42, 0xc1, 0xee, 0xfb, 0x5f, 0xd4, 0xd6, 0xdf, 0xfd, 0x36, 0xd3, 0x3, 0x4, 0xd, 0x90, 0x6, 0xb2, 0x25, 0x39, 0xe0, 0xd2, 0xf9, 0xcb, 0x6a, 0x60, 0x6f, 0x27, 0xb7, 0xbc, 0x58, 0xb7, 0x53, 0x4d, 0x0, 0xf2, 0x3f, 0x5e, 0x36, 0x43, 0x5f, 0xc3, 0xf0, 0xdf, 0x17, 0xd7, 0xa6, 0xae, 0x60, 0x10, 0xff, 0x57, 0x16, 0xc5, 0x5a, 0xf1, 0x60, 0xe3, 0xe7, 0x5f, 0x37, 0x46, 0x74, 0xba, 0x9a, 0x16, 0xef, 0x37, 0x1c, 0x6f, 0x61, 0x47, 0x1, 0xa5, 0xc7, 0x32, 0x47, 0x38, 0x12, 0x92, 0xb1, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; @@ -430,6 +446,10 @@ static const unsigned char unchecked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x4d, 0x4b, 0x59, 0x38, 0x37, 0x40, 0x20, 0x20, 0x24, 0x20, 0x20, 0x24, 0x38, 0x36, 0x40, 0x20, 0x20, 0x25, 0x1e, 0x1e, 0x22, 0x1f, 0x1f, 0x23, 0x20, 0x20, 0x24, 0x22, 0x22, 0x27, 0x23, 0x23, 0x28, 0x25, 0x25, 0x2a, 0x23, 0xc3, 0x49, 0x39, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xfa, 0xfb, 0xb4, 0xfa, 0xa4, 0x7f, 0xe1, 0x5a, 0x0, 0x0, 0x0, 0x4f, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xb5, 0xcf, 0x45, 0x2, 0x80, 0x40, 0x8, 0x0, 0x40, 0x97, 0x66, 0xfb, 0xff, 0x9f, 0xb5, 0xdb, 0xb3, 0x73, 0xa4, 0x19, 0xbe, 0x2, 0x20, 0xf1, 0x8a, 0x10, 0xc2, 0x1c, 0x0, 0xd1, 0x94, 0x57, 0x49, 0x5, 0xe6, 0x0, 0x6a, 0xa9, 0x6d, 0x55, 0x8b, 0xe2, 0x1c, 0xa0, 0x54, 0xfb, 0xae, 0x26, 0x9a, 0x3, 0x9c, 0xdb, 0x11, 0x68, 0x99, 0xff, 0xa, 0x7c, 0xd6, 0xde, 0xf, 0x33, 0x9c, 0x3, 0xe0, 0x76, 0x9c, 0x1e, 0x1d, 0xbe, 0xcf, 0x7d, 0x4c, 0x93, 0xe2, 0x8, 0xa4, 0x66, 0x3c, 0xec, 0xed, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; +static const unsigned char unchecked_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, 0x3, 0x0, 0x0, 0x0, 0x28, 0x2d, 0xf, 0x53, 0x0, 0x0, 0x0, 0x9, 0x70, 0x48, 0x59, 0x73, 0x0, 0x0, 0xb, 0x13, 0x0, 0x0, 0xb, 0x13, 0x1, 0x0, 0x9a, 0x9c, 0x18, 0x0, 0x0, 0x0, 0x33, 0x50, 0x4c, 0x54, 0x45, 0x0, 0x0, 0x0, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x7a, 0x78, 0x83, 0x6a, 0x69, 0x70, 0x6a, 0x68, 0x70, 0x58, 0x58, 0x5c, 0x58, 0x58, 0x5b, 0x58, 0x58, 0x5b, 0x5c, 0x5c, 0x5f, 0x5a, 0x5a, 0x5e, 0x59, 0x59, 0x5d, 0x58, 0x58, 0x5b, 0x57, 0x57, 0x5a, 0x56, 0x56, 0x59, 0x27, 0xa1, 0xa6, 0x53, 0x0, 0x0, 0x0, 0xb, 0x74, 0x52, 0x4e, 0x53, 0x0, 0x7, 0x27, 0x50, 0x66, 0x68, 0xb4, 0xb4, 0xfa, 0xfa, 0xfb, 0xc7, 0x8b, 0xf6, 0x7e, 0x0, 0x0, 0x0, 0x52, 0x49, 0x44, 0x41, 0x54, 0x78, 0x5e, 0xb5, 0xcf, 0x31, 0x12, 0xc0, 0x20, 0x8, 0x44, 0xd1, 0x15, 0x50, 0x83, 0x11, 0xe5, 0xfe, 0xa7, 0xcd, 0xe8, 0xc4, 0x22, 0xf4, 0x79, 0xe5, 0x36, 0x7c, 0x80, 0x8, 0x89, 0x58, 0xf2, 0x26, 0x4c, 0x9, 0x0, 0x15, 0xf5, 0xb9, 0xb9, 0x16, 0x2, 0xc0, 0x3a, 0xac, 0x6f, 0x36, 0x94, 0x1, 0x88, 0xdb, 0xfd, 0x32, 0x17, 0x0, 0x79, 0xf6, 0x33, 0xf4, 0x99, 0xff, 0x1a, 0xe2, 0xd9, 0x4f, 0x58, 0x5b, 0x61, 0x54, 0xdb, 0x49, 0xbf, 0xea, 0x4a, 0x8f, 0xcf, 0x45, 0xf, 0x4, 0x40, 0x7, 0x90, 0xb0, 0x7b, 0x47, 0x4, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 +}; + static const unsigned char updown_png[] = { 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd, 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x0, 0x8, 0x0, 0x0, 0x0, 0x10, 0x8, 0x4, 0x0, 0x0, 0x0, 0x81, 0x83, 0xf6, 0xf6, 0x0, 0x0, 0x0, 0x57, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0x8d, 0x4e, 0xb5, 0x1, 0xc0, 0x30, 0xc, 0xf3, 0x15, 0xfe, 0xff, 0x96, 0x64, 0xa, 0x6c, 0xca, 0x56, 0xd2, 0x25, 0x65, 0xe6, 0xc8, 0x8b, 0x49, 0x20, 0x79, 0x28, 0x95, 0x81, 0xa1, 0xd4, 0x7d, 0x4, 0xbb, 0xa1, 0x50, 0xea, 0x3c, 0xa6, 0x71, 0x98, 0x96, 0x69, 0x58, 0x31, 0xcc, 0xb7, 0xe5, 0x2f, 0x48, 0x63, 0x26, 0xf6, 0xa2, 0xd4, 0x18, 0xf9, 0x7, 0x2d, 0xe3, 0x46, 0x89, 0xb4, 0xd2, 0xf8, 0xa3, 0x68, 0xe3, 0xd7, 0x14, 0x20, 0xe6, 0xc3, 0x3d, 0xd8, 0xca, 0x5e, 0x94, 0x32, 0xd0, 0x3, 0x91, 0xba, 0x5f, 0x1b, 0x4a, 0x9b, 0x12, 0x62, 0x0, 0x0, 0x0, 0x0, 0x49, 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 }; diff --git a/scene/resources/default_theme/unchecked_disabled.png b/scene/resources/default_theme/unchecked_disabled.png Binary files differnew file mode 100644 index 0000000000..bef9316f58 --- /dev/null +++ b/scene/resources/default_theme/unchecked_disabled.png diff --git a/scene/resources/default_theme/xpmfix.sh b/scene/resources/default_theme/xpmfix.sh deleted file mode 100755 index a24dede3c9..0000000000 --- a/scene/resources/default_theme/xpmfix.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -sed -i 's/static char/static const char/g' *.xpm diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 32840dd373..c04b271d81 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,7 +44,7 @@ RID Environment::get_rid() const { void Environment::set_background(BGMode p_bg) { bg_mode = p_bg; RS::get_singleton()->environment_set_background(environment, RS::EnvironmentBG(p_bg)); - _change_notify(); + notify_property_list_changed(); if (bg_mode != BG_SKY) { set_fog_aerial_perspective(0.0); } @@ -138,7 +138,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(); + notify_property_list_changed(); } Environment::AmbientSource Environment::get_ambient_source() const { @@ -166,7 +166,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(); + notify_property_list_changed(); } Environment::ReflectionSource Environment::get_reflection_source() const { @@ -224,7 +224,7 @@ float Environment::get_tonemap_white() const { void Environment::set_tonemap_auto_exposure_enabled(bool p_enabled) { tonemap_auto_exposure_enabled = p_enabled; _update_tonemap(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_tonemap_auto_exposure_enabled() const { @@ -285,7 +285,7 @@ void Environment::_update_tonemap() { void Environment::set_ssr_enabled(bool p_enabled) { ssr_enabled = p_enabled; _update_ssr(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_ssr_enabled() const { @@ -343,7 +343,7 @@ void Environment::_update_ssr() { void Environment::set_ssao_enabled(bool p_enabled) { ssao_enabled = p_enabled; _update_ssao(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_ssao_enabled() const { @@ -441,6 +441,7 @@ void Environment::_update_ssao() { void Environment::set_sdfgi_enabled(bool p_enabled) { sdfgi_enabled = p_enabled; _update_sdfgi(); + notify_property_list_changed(); } bool Environment::is_sdfgi_enabled() const { @@ -458,8 +459,6 @@ Environment::SDFGICascades Environment::get_sdfgi_cascades() const { void Environment::set_sdfgi_min_cell_size(float p_size) { sdfgi_min_cell_size = p_size; - _change_notify("sdfgi_max_distance"); - _change_notify("sdfgi_cascade0_distance"); _update_sdfgi(); } @@ -475,8 +474,6 @@ void Environment::set_sdfgi_max_distance(float p_distance) { p_distance *= 0.5; //halve for each cascade } sdfgi_min_cell_size = p_distance; - _change_notify("sdfgi_min_cell_size"); - _change_notify("sdfgi_cascade0_distance"); _update_sdfgi(); } @@ -493,8 +490,6 @@ float Environment::get_sdfgi_max_distance() const { void Environment::set_sdfgi_cascade0_distance(float p_distance) { sdfgi_min_cell_size = p_distance / 64.0; - _change_notify("sdfgi_min_cell_size"); - _change_notify("sdfgi_max_distance"); _update_sdfgi(); } @@ -520,13 +515,12 @@ bool Environment::is_sdfgi_using_occlusion() const { return sdfgi_use_occlusion; } -void Environment::set_sdfgi_use_multi_bounce(bool p_enabled) { - sdfgi_use_multibounce = p_enabled; +void Environment::set_sdfgi_bounce_feedback(float p_amount) { + sdfgi_bounce_feedback = p_amount; _update_sdfgi(); } - -bool Environment::is_sdfgi_using_multi_bounce() const { - return sdfgi_use_multibounce; +float Environment::get_sdfgi_bounce_feedback() const { + return sdfgi_bounce_feedback; } void Environment::set_sdfgi_read_sky_light(bool p_enabled) { @@ -573,7 +567,7 @@ void Environment::_update_sdfgi() { sdfgi_min_cell_size, RS::EnvironmentSDFGIYScale(sdfgi_y_scale), sdfgi_use_occlusion, - sdfgi_use_multibounce, + sdfgi_bounce_feedback, sdfgi_read_sky_light, sdfgi_energy, sdfgi_normal_bias, @@ -585,7 +579,7 @@ void Environment::_update_sdfgi() { void Environment::set_glow_enabled(bool p_enabled) { glow_enabled = p_enabled; _update_glow(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_glow_enabled() const { @@ -655,7 +649,7 @@ float Environment::get_glow_bloom() const { void Environment::set_glow_blend_mode(GlowBlendMode p_mode) { glow_blend_mode = p_mode; _update_glow(); - _change_notify(); + notify_property_list_changed(); } Environment::GlowBlendMode Environment::get_glow_blend_mode() const { @@ -723,7 +717,7 @@ void Environment::_update_glow() { void Environment::set_fog_enabled(bool p_enabled) { fog_enabled = p_enabled; _update_fog(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_fog_enabled() const { @@ -797,13 +791,13 @@ void Environment::_update_fog() { // Volumetric Fog 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)); + 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, volumetric_fog_temporal_reproject, volumetric_fog_temporal_reproject_amount); } void Environment::set_volumetric_fog_enabled(bool p_enable) { volumetric_fog_enabled = p_enable; _update_volumetric_fog(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_volumetric_fog_enabled() const { @@ -854,13 +848,20 @@ float Environment::get_volumetric_fog_gi_inject() const { return volumetric_fog_gi_inject; } -void Environment::set_volumetric_fog_shadow_filter(VolumetricFogShadowFilter p_filter) { - volumetric_fog_shadow_filter = p_filter; +void Environment::set_volumetric_fog_temporal_reprojection_enabled(bool p_enable) { + volumetric_fog_temporal_reproject = p_enable; + _update_volumetric_fog(); +} +bool Environment::is_volumetric_fog_temporal_reprojection_enabled() const { + return volumetric_fog_temporal_reproject; +} +void Environment::set_volumetric_fog_temporal_reprojection_amount(float p_amount) { + volumetric_fog_temporal_reproject_amount = p_amount; _update_volumetric_fog(); } -Environment::VolumetricFogShadowFilter Environment::get_volumetric_fog_shadow_filter() const { - return volumetric_fog_shadow_filter; +float Environment::get_volumetric_fog_temporal_reprojection_amount() const { + return volumetric_fog_temporal_reproject_amount; } // Adjustment @@ -868,7 +869,7 @@ Environment::VolumetricFogShadowFilter Environment::get_volumetric_fog_shadow_fi void Environment::set_adjustment_enabled(bool p_enabled) { adjustment_enabled = p_enabled; _update_adjustment(); - _change_notify(); + notify_property_list_changed(); } bool Environment::is_adjustment_enabled() const { @@ -983,6 +984,7 @@ void Environment::_validate_property(PropertyInfo &property) const { "auto_exposure_", "ss_reflections_", "ssao_", + "sdfgi_", "glow_", "adjustment_", nullptr @@ -1200,8 +1202,8 @@ void Environment::_bind_methods() { ClassDB::bind_method(D_METHOD("get_sdfgi_y_scale"), &Environment::get_sdfgi_y_scale); ClassDB::bind_method(D_METHOD("set_sdfgi_use_occlusion", "enable"), &Environment::set_sdfgi_use_occlusion); ClassDB::bind_method(D_METHOD("is_sdfgi_using_occlusion"), &Environment::is_sdfgi_using_occlusion); - ClassDB::bind_method(D_METHOD("set_sdfgi_use_multi_bounce", "enable"), &Environment::set_sdfgi_use_multi_bounce); - ClassDB::bind_method(D_METHOD("is_sdfgi_using_multi_bounce"), &Environment::is_sdfgi_using_multi_bounce); + ClassDB::bind_method(D_METHOD("set_sdfgi_bounce_feedback", "amount"), &Environment::set_sdfgi_bounce_feedback); + ClassDB::bind_method(D_METHOD("get_sdfgi_bounce_feedback"), &Environment::get_sdfgi_bounce_feedback); ClassDB::bind_method(D_METHOD("set_sdfgi_read_sky_light", "enable"), &Environment::set_sdfgi_read_sky_light); ClassDB::bind_method(D_METHOD("is_sdfgi_reading_sky_light"), &Environment::is_sdfgi_reading_sky_light); ClassDB::bind_method(D_METHOD("set_sdfgi_energy", "amount"), &Environment::set_sdfgi_energy); @@ -1213,9 +1215,9 @@ void Environment::_bind_methods() { ADD_GROUP("SDFGI", "sdfgi_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_enabled"), "set_sdfgi_enabled", "is_sdfgi_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_multi_bounce"), "set_sdfgi_use_multi_bounce", "is_sdfgi_using_multi_bounce"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_use_occlusion"), "set_sdfgi_use_occlusion", "is_sdfgi_using_occlusion"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sdfgi_read_sky_light"), "set_sdfgi_read_sky_light", "is_sdfgi_reading_sky_light"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_bounce_feedback", PROPERTY_HINT_RANGE, "0,1.99,0.01"), "set_sdfgi_bounce_feedback", "get_sdfgi_bounce_feedback"); ADD_PROPERTY(PropertyInfo(Variant::INT, "sdfgi_cascades", PROPERTY_HINT_ENUM, "4 Cascades,6 Cascades,8 Cascades"), "set_sdfgi_cascades", "get_sdfgi_cascades"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_min_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_sdfgi_min_cell_size", "get_sdfgi_min_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sdfgi_cascade0_distance", PROPERTY_HINT_RANGE, "0.1,16384,0.1,or_greater"), "set_sdfgi_cascade0_distance", "get_sdfgi_cascade0_distance"); @@ -1317,8 +1319,10 @@ void Environment::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_enabled", "enabled"), &Environment::set_volumetric_fog_temporal_reprojection_enabled); + ClassDB::bind_method(D_METHOD("is_volumetric_fog_temporal_reprojection_enabled"), &Environment::is_volumetric_fog_temporal_reprojection_enabled); + ClassDB::bind_method(D_METHOD("set_volumetric_fog_temporal_reprojection_amount", "temporal_reprojection_amount"), &Environment::set_volumetric_fog_temporal_reprojection_amount); + ClassDB::bind_method(D_METHOD("get_volumetric_fog_temporal_reprojection_amount"), &Environment::get_volumetric_fog_temporal_reprojection_amount); ADD_GROUP("Volumetric Fog", "volumetric_fog_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_enabled"), "set_volumetric_fog_enabled", "is_volumetric_fog_enabled"); @@ -1328,7 +1332,9 @@ void Environment::_bind_methods() { 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"); + ADD_SUBGROUP("Temporal Reprojection", "volumetric_fog_temporal_reprojection_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "volumetric_fog_temporal_reprojection_enabled"), "set_volumetric_fog_temporal_reprojection_enabled", "is_volumetric_fog_temporal_reprojection_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "volumetric_fog_temporal_reprojection_amount", PROPERTY_HINT_RANGE, "0.0,0.999,0.001"), "set_volumetric_fog_temporal_reprojection_amount", "get_volumetric_fog_temporal_reprojection_amount"); // Adjustment @@ -1417,7 +1423,7 @@ Environment::Environment() { _update_fog(); _update_adjustment(); _update_volumetric_fog(); - _change_notify(); + notify_property_list_changed(); } Environment::~Environment() { diff --git a/scene/resources/environment.h b/scene/resources/environment.h index a720f2cc47..0df2c3cc27 100644 --- a/scene/resources/environment.h +++ b/scene/resources/environment.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -103,7 +103,7 @@ private: // Background BGMode bg_mode = BG_CLEAR_COLOR; Ref<Sky> bg_sky; - float bg_sky_custom_fov = 0; + float bg_sky_custom_fov = 0.0; Vector3 bg_sky_rotation; Color bg_color; float bg_energy = 1.0; @@ -125,7 +125,7 @@ private: float tonemap_white = 1.0; bool tonemap_auto_exposure_enabled = false; float tonemap_auto_exposure_min = 0.05; - float tonemap_auto_exposure_max = 8; + float tonemap_auto_exposure_max = 8.0; float tonemap_auto_exposure_speed = 0.5; float tonemap_auto_exposure_grey = 0.4; void _update_tonemap(); @@ -156,7 +156,7 @@ private: float sdfgi_min_cell_size = 0.2; SDFGIYScale sdfgi_y_scale = SDFGI_Y_SCALE_DISABLED; bool sdfgi_use_occlusion = false; - bool sdfgi_use_multibounce = false; + float sdfgi_bounce_feedback = 0.0; bool sdfgi_read_sky_light = false; float sdfgi_energy = 1.0; float sdfgi_normal_bias = 1.1; @@ -196,8 +196,9 @@ private: 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; + bool volumetric_fog_temporal_reproject = true; + float volumetric_fog_temporal_reproject_amount = 0.9; void _update_volumetric_fog(); // Adjustment @@ -317,8 +318,8 @@ public: SDFGIYScale get_sdfgi_y_scale() const; void set_sdfgi_use_occlusion(bool p_enabled); bool is_sdfgi_using_occlusion() const; - void set_sdfgi_use_multi_bounce(bool p_enabled); - bool is_sdfgi_using_multi_bounce() const; + void set_sdfgi_bounce_feedback(float p_amount); + float get_sdfgi_bounce_feedback() const; void set_sdfgi_read_sky_light(bool p_enabled); bool is_sdfgi_reading_sky_light() const; void set_sdfgi_energy(float p_energy); @@ -385,10 +386,12 @@ public: 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; + void set_volumetric_fog_temporal_reprojection_enabled(bool p_enable); + bool is_volumetric_fog_temporal_reprojection_enabled() const; + void set_volumetric_fog_temporal_reprojection_amount(float p_amount); + float get_volumetric_fog_temporal_reprojection_amount() const; // Adjustment void set_adjustment_enabled(bool p_enabled); diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index 791f260c0e..6f87c524d8 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,6 +39,11 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("load_resource", "filename", "base_size"), &FontData::load_resource, DEFVAL(16)); ClassDB::bind_method(D_METHOD("load_memory", "data", "type", "base_size"), &FontData::_load_memory, DEFVAL(16)); + ClassDB::bind_method(D_METHOD("new_bitmap", "height", "ascent", "base_size"), &FontData::new_bitmap); + + ClassDB::bind_method(D_METHOD("bitmap_add_texture", "texture"), &FontData::bitmap_add_texture); + ClassDB::bind_method(D_METHOD("bitmap_add_char", "char", "texture_idx", "rect", "align", "advance"), &FontData::bitmap_add_char); + ClassDB::bind_method(D_METHOD("bitmap_add_kerning_pair", "A", "B", "kerning"), &FontData::bitmap_add_kerning_pair); ClassDB::bind_method(D_METHOD("set_data_path", "path"), &FontData::set_data_path); ClassDB::bind_method(D_METHOD("get_data_path"), &FontData::get_data_path); @@ -50,6 +55,9 @@ void FontData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_underline_position", "size"), &FontData::get_underline_position); ClassDB::bind_method(D_METHOD("get_underline_thickness", "size"), &FontData::get_underline_thickness); + ClassDB::bind_method(D_METHOD("get_spacing", "type"), &FontData::get_spacing); + ClassDB::bind_method(D_METHOD("set_spacing", "type", "value"), &FontData::set_spacing); + ClassDB::bind_method(D_METHOD("set_antialiased", "antialiased"), &FontData::set_antialiased); ClassDB::bind_method(D_METHOD("get_antialiased"), &FontData::get_antialiased); @@ -100,6 +108,13 @@ void FontData::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_field_hint"), "set_distance_field_hint", "get_distance_field_hint"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting"); + + ADD_GROUP("Extra Spacing", "extra_spacing"); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_glyph"), "set_spacing", "get_spacing", SPACING_GLYPH); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "extra_spacing_space"), "set_spacing", "get_spacing", SPACING_SPACE); + + BIND_ENUM_CONSTANT(SPACING_GLYPH); + BIND_ENUM_CONSTANT(SPACING_SPACE); } bool FontData::_set(const StringName &p_name, const Variant &p_value) { @@ -177,6 +192,14 @@ void FontData::_get_property_list(List<PropertyInfo> *p_list) const { } } +void FontData::reset_state() { + if (rid != RID()) { + TS->free(rid); + } + base_size = 16; + path = String(); +} + RID FontData::get_rid() const { return rid; } @@ -211,6 +234,34 @@ void FontData::load_memory(const uint8_t *p_data, size_t p_size, const String &p emit_changed(); } +void FontData::new_bitmap(float p_height, float p_ascent, int p_base_size) { + if (rid != RID()) { + TS->free(rid); + } + rid = TS->create_font_bitmap(p_height, p_ascent, p_base_size); + path = TTR("(Bitmap: " + String::num_int64(rid.get_id(), 16, true) + ")"); + base_size = TS->font_get_base_size(rid); + emit_changed(); +} + +void FontData::bitmap_add_texture(const Ref<Texture> &p_texture) { + if (rid != RID()) { + TS->font_bitmap_add_texture(rid, p_texture); + } +} + +void FontData::bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance) { + if (rid != RID()) { + TS->font_bitmap_add_char(rid, p_char, p_texture_idx, p_rect, p_align, p_advance); + } +} + +void FontData::bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning) { + if (rid != RID()) { + TS->font_bitmap_add_kerning_pair(rid, p_A, p_B, p_kerning); + } +} + void FontData::set_data_path(const String &p_path) { load_resource(p_path, base_size); } @@ -281,6 +332,27 @@ double FontData::get_variation(const String &p_name) const { return TS->font_get_variation(rid, p_name); } +int FontData::get_spacing(int p_type) const { + if (rid == RID()) { + return 0; + } + if (p_type == SPACING_GLYPH) { + return TS->font_get_spacing_glyph(rid); + } else { + return TS->font_get_spacing_space(rid); + } +} + +void FontData::set_spacing(int p_type, int p_value) { + ERR_FAIL_COND(rid == RID()); + if (p_type == SPACING_GLYPH) { + TS->font_set_spacing_glyph(rid, p_value); + } else { + TS->font_set_spacing_space(rid, p_value); + } + emit_changed(); +} + void FontData::set_antialiased(bool p_antialiased) { ERR_FAIL_COND(rid == RID()); TS->font_set_antialiased(rid, p_antialiased); @@ -509,7 +581,7 @@ void Font::_data_changed() { cache_wrap.clear(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } bool Font::_set(const StringName &p_name, const Variant &p_value) { @@ -588,6 +660,14 @@ void Font::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::OBJECT, "data/" + itos(data.size()), PROPERTY_HINT_RESOURCE_TYPE, "FontData")); } +void Font::reset_state() { + spacing_top = 0; + spacing_bottom = 0; + cache.clear(); + cache_wrap.clear(); + data.clear(); +} + void Font::add_data(const Ref<FontData> &p_data) { ERR_FAIL_COND(p_data.is_null()); data.push_back(p_data); @@ -600,7 +680,7 @@ void Font::add_data(const Ref<FontData> &p_data) { cache_wrap.clear(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void Font::set_data(int p_idx, const Ref<FontData> &p_data) { @@ -621,7 +701,7 @@ void Font::set_data(int p_idx, const Ref<FontData> &p_data) { cache_wrap.clear(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } int Font::get_data_count() const { @@ -646,7 +726,7 @@ void Font::remove_data(int p_idx) { cache_wrap.clear(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } Dictionary Font::get_feature_list() const { @@ -718,13 +798,13 @@ void Font::set_spacing(int p_type, int p_value) { } emit_changed(); - _change_notify(); + notify_property_list_changed(); } // Drawing string and string sizes, cached. Size2 Font::get_string_size(const String &p_text, int p_size) const { - ERR_FAIL_COND_V(data.empty(), Size2()); + ERR_FAIL_COND_V(data.is_empty(), Size2()); uint64_t hash = p_text.hash64(); hash = hash_djb2_one_64(p_size, hash); @@ -746,7 +826,7 @@ Size2 Font::get_string_size(const String &p_text, int p_size) const { } Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p_size, uint8_t p_flags) const { - ERR_FAIL_COND_V(data.empty(), Size2()); + ERR_FAIL_COND_V(data.is_empty(), Size2()); uint64_t hash = p_text.hash64(); hash = hash_djb2_one_64(p_size, hash); @@ -781,6 +861,8 @@ Size2 Font::get_multiline_string_size(const String &p_text, float p_width, int p } void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { + ERR_FAIL_COND(data.is_empty()); + uint64_t hash = p_text.hash64(); hash = hash_djb2_one_64(p_size, hash); @@ -811,6 +893,8 @@ void Font::draw_string(RID p_canvas_item, const Point2 &p_pos, const String &p_t } void Font::draw_multiline_string(RID p_canvas_item, const Point2 &p_pos, const String &p_text, HAlign p_align, float p_width, int p_max_lines, int p_size, const Color &p_modulate, int p_outline_size, const Color &p_outline_modulate, uint8_t p_flags) const { + ERR_FAIL_COND(data.is_empty()); + uint64_t hash = p_text.hash64(); hash = hash_djb2_one_64(p_size, hash); @@ -951,7 +1035,7 @@ Font::~Font() { /*************************************************************************/ -RES ResourceFormatLoaderFont::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) { +RES ResourceFormatLoaderFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } @@ -1006,7 +1090,7 @@ String ResourceFormatLoaderFont::get_resource_type(const String &p_path) const { #ifndef DISABLE_DEPRECATED -RES ResourceFormatLoaderCompatFont::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) { +RES ResourceFormatLoaderCompatFont::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } diff --git a/scene/resources/font.h b/scene/resources/font.h index fe28e1aea5..200373aa8c 100644 --- a/scene/resources/font.h +++ b/scene/resources/font.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,6 +42,13 @@ class FontData : public Resource { GDCLASS(FontData, Resource); +public: + enum SpacingType { + SPACING_GLYPH, + SPACING_SPACE, + }; + +private: RID rid; int base_size = 16; String path; @@ -53,6 +60,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + public: virtual RID get_rid() const override; @@ -60,6 +69,12 @@ public: void load_memory(const uint8_t *p_data, size_t p_size, const String &p_type, int p_base_size = 16); void _load_memory(const PackedByteArray &p_data, const String &p_type, int p_base_size = 16); + void new_bitmap(float p_height, float p_ascent, int p_base_size = 16); + + void bitmap_add_texture(const Ref<Texture> &p_texture); + void bitmap_add_char(char32_t p_char, int p_texture_idx, const Rect2 &p_rect, const Size2 &p_align, float p_advance); + void bitmap_add_kerning_pair(char32_t p_A, char32_t p_B, int p_kerning); + void set_data_path(const String &p_path); String get_data_path() const; @@ -76,6 +91,9 @@ public: float get_underline_position(int p_size) const; float get_underline_thickness(int p_size) const; + int get_spacing(int p_type) const; + void set_spacing(int p_type, int p_value); + void set_antialiased(bool p_antialiased); bool get_antialiased() const; @@ -132,7 +150,7 @@ class Font : public Resource { public: enum SpacingType { SPACING_TOP, - SPACING_BOTTOM + SPACING_BOTTOM, }; private: @@ -151,6 +169,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + void _data_changed(); public: @@ -195,13 +215,14 @@ public: ~Font(); }; +VARIANT_ENUM_CAST(FontData::SpacingType); VARIANT_ENUM_CAST(Font::SpacingType); /*************************************************************************/ class ResourceFormatLoaderFont : 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 RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; @@ -212,7 +233,7 @@ public: class ResourceFormatLoaderCompatFont : 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 RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; diff --git a/scene/resources/gradient.cpp b/scene/resources/gradient.cpp index 6b41b97e45..7b9b942142 100644 --- a/scene/resources/gradient.cpp +++ b/scene/resources/gradient.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,7 +39,6 @@ Gradient::Gradient() { points.write[0].offset = 0; points.write[1].color = Color(1, 1, 1, 1); points.write[1].offset = 1; - is_sorted = true; } Gradient::~Gradient() { @@ -47,7 +46,7 @@ Gradient::~Gradient() { void Gradient::_bind_methods() { ClassDB::bind_method(D_METHOD("add_point", "offset", "color"), &Gradient::add_point); - ClassDB::bind_method(D_METHOD("remove_point", "offset"), &Gradient::remove_point); + ClassDB::bind_method(D_METHOD("remove_point", "point"), &Gradient::remove_point); ClassDB::bind_method(D_METHOD("set_offset", "point", "offset"), &Gradient::set_offset); ClassDB::bind_method(D_METHOD("get_offset", "point"), &Gradient::get_offset); diff --git a/scene/resources/gradient.h b/scene/resources/gradient.h index e839909770..cf5b179c45 100644 --- a/scene/resources/gradient.h +++ b/scene/resources/gradient.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,7 +39,7 @@ class Gradient : public Resource { public: struct Point { - float offset; + float offset = 0.0; Color color; bool operator<(const Point &p_ponit) const { return offset < p_ponit.offset; @@ -48,7 +48,7 @@ public: private: Vector<Point> points; - bool is_sorted; + bool is_sorted = true; _FORCE_INLINE_ void _update_sorting() { if (!is_sorted) { points.sort(); @@ -82,7 +82,7 @@ public: Vector<Color> get_colors() const; _FORCE_INLINE_ Color get_color_at_offset(float p_offset) { - if (points.empty()) { + if (points.is_empty()) { return Color(0, 0, 0, 1); } diff --git a/scene/resources/height_map_shape_3d.cpp b/scene/resources/height_map_shape_3d.cpp index 2ae47bcf3c..5593bb766f 100644 --- a/scene/resources/height_map_shape_3d.cpp +++ b/scene/resources/height_map_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -107,8 +107,6 @@ void HeightMapShape3D::set_map_width(int p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_width"); - _change_notify("map_data"); } } @@ -133,8 +131,6 @@ void HeightMapShape3D::set_map_depth(int p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_depth"); - _change_notify("map_data"); } } @@ -171,7 +167,6 @@ void HeightMapShape3D::set_map_data(PackedFloat32Array p_new) { _update_shape(); notify_change_to_owners(); - _change_notify("map_data"); } PackedFloat32Array HeightMapShape3D::get_map_data() const { @@ -193,16 +188,12 @@ void HeightMapShape3D::_bind_methods() { HeightMapShape3D::HeightMapShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_HEIGHTMAP)) { - map_width = 2; - map_depth = 2; map_data.resize(map_width * map_depth); real_t *w = map_data.ptrw(); w[0] = 0.0; w[1] = 0.0; w[2] = 0.0; w[3] = 0.0; - min_height = 0.0; - max_height = 0.0; _update_shape(); } diff --git a/scene/resources/height_map_shape_3d.h b/scene/resources/height_map_shape_3d.h index 9ee8b49689..6fc88cff90 100644 --- a/scene/resources/height_map_shape_3d.h +++ b/scene/resources/height_map_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,11 +36,11 @@ class HeightMapShape3D : public Shape3D { GDCLASS(HeightMapShape3D, Shape3D); - int map_width; - int map_depth; + int map_width = 2; + int map_depth = 2; PackedFloat32Array map_data; - float min_height; - float max_height; + float min_height = 0.0; + float max_height = 0.0; protected: static void _bind_methods(); diff --git a/scene/resources/line_shape_2d.cpp b/scene/resources/line_shape_2d.cpp index 58653c5f4a..d206f12287 100644 --- a/scene/resources/line_shape_2d.cpp +++ b/scene/resources/line_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { Vector2 point = get_distance() * get_normal(); - Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } }; + Vector2 l[2][2] = { { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }, { point, point + get_normal() * 30 } }; for (int i = 0; i < 2; i++) { Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, l[i]); @@ -77,7 +77,7 @@ real_t LineShape2D::get_distance() const { void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { Vector2 point = get_distance() * get_normal(); - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; RS::get_singleton()->canvas_item_add_line(p_to_rid, l1[0], l1[1], p_color, 3); Vector2 l2[2] = { point, point + get_normal() * 30 }; RS::get_singleton()->canvas_item_add_line(p_to_rid, l2[0], l2[1], p_color, 3); @@ -86,7 +86,7 @@ void LineShape2D::draw(const RID &p_to_rid, const Color &p_color) { Rect2 LineShape2D::get_rect() const { Vector2 point = get_distance() * get_normal(); - Vector2 l1[2] = { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }; + Vector2 l1[2] = { point - get_normal().orthogonal() * 100, point + get_normal().orthogonal() * 100 }; Vector2 l2[2] = { point, point + get_normal() * 30 }; Rect2 rect; rect.position = l1[0]; @@ -113,7 +113,5 @@ void LineShape2D::_bind_methods() { LineShape2D::LineShape2D() : Shape2D(PhysicsServer2D::get_singleton()->line_shape_create()) { - normal = Vector2(0, 1); - distance = 0; _update_shape(); } diff --git a/scene/resources/line_shape_2d.h b/scene/resources/line_shape_2d.h index 7e67a8f67c..9f0405ad29 100644 --- a/scene/resources/line_shape_2d.h +++ b/scene/resources/line_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,8 +36,8 @@ class LineShape2D : public Shape2D { GDCLASS(LineShape2D, Shape2D); - Vector2 normal; - real_t distance; + Vector2 normal = Vector2(0, 1); + real_t distance = 0.0; void _update_shape(); diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 6e08af23f5..0d02bde90d 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,6 +36,7 @@ #include "editor/editor_settings.h" #endif +#include "scene/main/scene_tree.h" #include "scene/scene_string_names.h" void Material::set_next_pass(const Ref<Material> &p_pass) { @@ -80,6 +81,14 @@ void Material::_validate_property(PropertyInfo &property) const { } } +void Material::inspect_native_shader_code() { + SceneTree *st = Object::cast_to<SceneTree>(OS::get_singleton()->get_main_loop()); + RID shader = get_shader_rid(); + if (st && shader.is_valid()) { + st->call_group("_native_shader_source_visualizer", "_inspect_shader", shader); + } +} + void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_next_pass", "next_pass"), &Material::set_next_pass); ClassDB::bind_method(D_METHOD("get_next_pass"), &Material::get_next_pass); @@ -87,6 +96,9 @@ void Material::_bind_methods() { ClassDB::bind_method(D_METHOD("set_render_priority", "priority"), &Material::set_render_priority); ClassDB::bind_method(D_METHOD("get_render_priority"), &Material::get_render_priority); + ClassDB::bind_method(D_METHOD("inspect_native_shader_code"), &Material::inspect_native_shader_code); + ClassDB::set_method_flags(get_class_static(), _scs_create("inspect_native_shader_code"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ADD_PROPERTY(PropertyInfo(Variant::INT, "render_priority", PROPERTY_HINT_RANGE, itos(RENDER_PRIORITY_MIN) + "," + itos(RENDER_PRIORITY_MAX) + ",1"), "set_render_priority", "get_render_priority"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "next_pass", PROPERTY_HINT_RESOURCE_TYPE, "Material"), "set_next_pass", "get_next_pass"); @@ -180,7 +192,7 @@ Variant ShaderMaterial::property_get_revert(const String &p_name) { void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) { // Only connect/disconnect the signal when running in the editor. - // This can be a slow operation, and `_change_notify()` (which is called by `_shader_changed()`) + // This can be a slow operation, and `notify_property_list_changed()` (which is called by `_shader_changed()`) // does nothing in non-editor builds anyway. See GH-34741 for details. if (shader.is_valid() && Engine::get_singleton()->is_editor_hint()) { shader->disconnect("changed", callable_mp(this, &ShaderMaterial::_shader_changed)); @@ -198,7 +210,7 @@ void ShaderMaterial::set_shader(const Ref<Shader> &p_shader) { } RS::get_singleton()->material_set_shader(_get_material(), rid); - _change_notify(); //properties for shader exposed + notify_property_list_changed(); //properties for shader exposed emit_changed(); } @@ -215,7 +227,7 @@ Variant ShaderMaterial::get_shader_param(const StringName &p_param) const { } void ShaderMaterial::_shader_changed() { - _change_notify(); //update all properties + notify_property_list_changed(); //update all properties } void ShaderMaterial::_bind_methods() { @@ -260,6 +272,13 @@ Shader::Mode ShaderMaterial::get_shader_mode() const { return Shader::MODE_SPATIAL; } } +RID ShaderMaterial::get_shader_rid() const { + if (shader.is_valid()) { + return shader->get_rid(); + } else { + return RID(); + } +} ShaderMaterial::ShaderMaterial() { } @@ -716,7 +735,7 @@ void BaseMaterial3D::_update_shader() { if (flags[FLAG_SRGB_VERTEX_COLOR]) { code += "\tif (!OUTPUT_IS_SRGB) {\n"; - code += "\t\tCOLOR.rgb = mix( pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb* (1.0 / 12.92), lessThan(COLOR.rgb,vec3(0.04045)) );\n"; + code += "\t\tCOLOR.rgb = mix(pow((COLOR.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), COLOR.rgb * (1.0 / 12.92), lessThan(COLOR.rgb, vec3(0.04045)));\n"; code += "\t}\n"; } if (flags[FLAG_USE_POINT_SIZE]) { @@ -969,11 +988,11 @@ void BaseMaterial3D::_update_shader() { if (features[FEATURE_NORMAL_MAPPING]) { if (flags[FLAG_UV1_USE_TRIPLANAR]) { - code += "\tNORMALMAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; + code += "\tNORMAL_MAP = triplanar_texture(texture_normal,uv1_power_normal,uv1_triplanar_pos).rgb;\n"; } else { - code += "\tNORMALMAP = texture(texture_normal,base_uv).rgb;\n"; + code += "\tNORMAL_MAP = texture(texture_normal,base_uv).rgb;\n"; } - code += "\tNORMALMAP_DEPTH = normal_scale;\n"; + code += "\tNORMAL_MAP_DEPTH = normal_scale;\n"; } if (features[FEATURE_EMISSION]) { @@ -1000,7 +1019,7 @@ void BaseMaterial3D::_update_shader() { if (features[FEATURE_REFRACTION]) { if (features[FEATURE_NORMAL_MAPPING]) { - code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n"; + code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMAL_MAP.x + BINORMAL * NORMAL_MAP.y + NORMAL * NORMAL_MAP.z,NORMAL_MAP_DEPTH) );\n"; } else { code += "\tvec3 ref_normal = NORMAL;\n"; } @@ -1198,8 +1217,8 @@ void BaseMaterial3D::_update_shader() { break; // Internal value, skip. } - code += "\tvec3 detail_norm = mix(NORMALMAP,detail_norm_tex.rgb,detail_tex.a);\n"; - code += "\tNORMALMAP = mix(NORMALMAP,detail_norm,detail_mask_tex.r);\n"; + code += "\tvec3 detail_norm = mix(NORMAL_MAP,detail_norm_tex.rgb,detail_tex.a);\n"; + code += "\tNORMAL_MAP = mix(NORMAL_MAP,detail_norm,detail_mask_tex.r);\n"; code += "\tALBEDO.rgb = mix(ALBEDO.rgb,detail,detail_mask_tex.r);\n"; } @@ -1470,7 +1489,7 @@ void BaseMaterial3D::set_transparency(Transparency p_transparency) { transparency = p_transparency; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::Transparency BaseMaterial3D::get_transparency() const { @@ -1484,7 +1503,7 @@ void BaseMaterial3D::set_alpha_antialiasing(AlphaAntiAliasing p_alpha_aa) { alpha_antialiasing_mode = p_alpha_aa; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::AlphaAntiAliasing BaseMaterial3D::get_alpha_antialiasing() const { @@ -1498,7 +1517,7 @@ void BaseMaterial3D::set_shading_mode(ShadingMode p_shading_mode) { shading_mode = p_shading_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::ShadingMode BaseMaterial3D::get_shading_mode() const { @@ -1565,8 +1584,8 @@ void BaseMaterial3D::set_flag(Flags p_flag, bool p_enabled) { } flags[p_flag] = p_enabled; - if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN) { - _change_notify(); + if (p_flag == FLAG_USE_SHADOW_TO_OPACITY || p_flag == FLAG_USE_TEXTURE_REPEAT || p_flag == FLAG_SUBSURFACE_MODE_SKIN || p_flag == FLAG_USE_POINT_SIZE) { + notify_property_list_changed(); } _queue_shader_change(); } @@ -1583,7 +1602,7 @@ void BaseMaterial3D::set_feature(Feature p_feature, bool p_enabled) { } features[p_feature] = p_enabled; - _change_notify(); + notify_property_list_changed(); _queue_shader_change(); } @@ -1601,7 +1620,7 @@ void BaseMaterial3D::set_texture(TextureParam p_param, const Ref<Texture2D> &p_t RS::get_singleton()->material_set_param(_get_material(), shader_names->albedo_texture_size, Vector2i(p_texture->get_width(), p_texture->get_height())); } - _change_notify(); + notify_property_list_changed(); _queue_shader_change(); } @@ -1631,7 +1650,7 @@ BaseMaterial3D::TextureFilter BaseMaterial3D::get_texture_filter() const { void BaseMaterial3D::_validate_feature(const String &text, Feature feature, PropertyInfo &property) const { if (property.name.begins_with(text) && property.name != text + "_enabled" && !features[feature]) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NOEDITOR; } } @@ -1664,19 +1683,27 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.usage = 0; } - if (property.name == "params_grow_amount" && !grow_enabled) { - property.usage = 0; + if (property.name == "billboard_keep_scale" && billboard_mode == BILLBOARD_DISABLED) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + + if (property.name == "grow_amount" && !grow_enabled) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + + if (property.name == "point_size" && !flags[FLAG_USE_POINT_SIZE]) { + property.usage = PROPERTY_USAGE_NOEDITOR; } if (property.name == "proximity_fade_distance" && !proximity_fade_enabled) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NOEDITOR; } if ((property.name == "distance_fade_max_distance" || property.name == "distance_fade_min_distance") && distance_fade == DISTANCE_FADE_DISABLED) { - property.usage = 0; + property.usage = PROPERTY_USAGE_NOEDITOR; } - // you can only enable anti-aliasing (in mataerials) on alpha scissor and alpha hash + // you can only enable anti-aliasing (in materials) 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; @@ -1695,7 +1722,7 @@ void BaseMaterial3D::_validate_property(PropertyInfo &property) const { property.usage = 0; } - // we cant choose an antialiasing mode if alpha isnt possible + // we can't choose an antialiasing mode if alpha isn't possible if (property.name == "alpha_antialiasing_edge" && !alpha_aa_enabled) { property.usage = 0; } @@ -1841,7 +1868,7 @@ float BaseMaterial3D::get_uv2_triplanar_blend_sharpness() const { void BaseMaterial3D::set_billboard_mode(BillboardMode p_mode) { billboard_mode = p_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::BillboardMode BaseMaterial3D::get_billboard_mode() const { @@ -1878,7 +1905,7 @@ bool BaseMaterial3D::get_particles_anim_loop() const { void BaseMaterial3D::set_heightmap_deep_parallax(bool p_enable) { deep_parallax = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_heightmap_deep_parallax_enabled() const { @@ -1924,7 +1951,7 @@ bool BaseMaterial3D::get_heightmap_deep_parallax_flip_binormal() const { void BaseMaterial3D::set_grow_enabled(bool p_enable) { grow_enabled = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_grow_enabled() const { @@ -2074,7 +2101,7 @@ void BaseMaterial3D::set_on_top_of_alpha() { void BaseMaterial3D::set_proximity_fade(bool p_enable) { proximity_fade_enabled = p_enable; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } bool BaseMaterial3D::is_proximity_fade_enabled() const { @@ -2093,7 +2120,7 @@ float BaseMaterial3D::get_proximity_fade_distance() const { void BaseMaterial3D::set_distance_fade(DistanceFadeMode p_mode) { distance_fade = p_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } BaseMaterial3D::DistanceFadeMode BaseMaterial3D::get_distance_fade() const { @@ -2636,9 +2663,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : element(this) { orm = p_orm; // Initialize to the same values as the shader - 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); @@ -2670,7 +2694,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_particles_anim_h_frames(1); set_particles_anim_v_frames(1); set_particles_anim_loop(false); - emission_op = EMISSION_OP_ADD; set_transparency(TRANSPARENCY_DISABLED); set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF); @@ -2678,8 +2701,6 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : 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); set_distance_fade_min_distance(0); set_distance_fade_max_distance(10); @@ -2691,35 +2712,14 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) : set_ao_texture_channel(TEXTURE_CHANNEL_RED); set_refraction_texture_channel(TEXTURE_CHANNEL_RED); - grow_enabled = false; set_grow(0.0); - deep_parallax = false; - heightmap_parallax_flip_tangent = false; - heightmap_parallax_flip_binormal = false; set_heightmap_deep_parallax_min_layers(8); set_heightmap_deep_parallax_max_layers(32); set_heightmap_deep_parallax_flip_tangent(false); //also sets binormal - detail_uv = DETAIL_UV_1; - blend_mode = BLEND_MODE_MIX; - detail_blend_mode = BLEND_MODE_MIX; - depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY; - cull_mode = CULL_BACK; - for (int i = 0; i < FLAG_MAX; i++) { - flags[i] = false; - } flags[FLAG_USE_TEXTURE_REPEAT] = true; - diffuse_mode = DIFFUSE_BURLEY; - specular_mode = SPECULAR_SCHLICK_GGX; - - for (int i = 0; i < FEATURE_MAX; i++) { - features[i] = false; - } - - texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; - _queue_shader_change(); } diff --git a/scene/resources/material.h b/scene/resources/material.h index caf28eea18..70452a5f74 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,6 +47,8 @@ class Material : public Resource { Ref<Material> next_pass; int render_priority; + void inspect_native_shader_code(); + protected: _FORCE_INLINE_ RID _get_material() const { return material; } static void _bind_methods(); @@ -66,6 +68,7 @@ public: int get_render_priority() const; virtual RID get_rid() const override; + virtual RID get_shader_rid() const = 0; virtual Shader::Mode get_shader_mode() const = 0; Material(); @@ -100,6 +103,8 @@ public: virtual Shader::Mode get_shader_mode() const override; + virtual RID get_shader_rid() const override; + ShaderMaterial(); ~ShaderMaterial(); }; @@ -325,7 +330,7 @@ private: struct ShaderData { RID shader; - int users; + int users = 0; }; static Map<MaterialKey, ShaderData> shader_map; @@ -463,16 +468,16 @@ private: float alpha_scissor_threshold; float alpha_hash_scale; float alpha_antialiasing_edge; - bool grow_enabled; + bool grow_enabled = false; float ao_light_affect; float grow; int particles_anim_h_frames; int particles_anim_v_frames; bool particles_anim_loop; - Transparency transparency; - ShadingMode shading_mode; + Transparency transparency = TRANSPARENCY_DISABLED; + ShadingMode shading_mode = SHADING_MODE_PER_PIXEL; - TextureFilter texture_filter; + TextureFilter texture_filter = TEXTURE_FILTER_LINEAR_WITH_MIPMAPS; Vector3 uv1_scale; Vector3 uv1_offset; @@ -482,39 +487,39 @@ private: Vector3 uv2_offset; float uv2_triplanar_sharpness; - DetailUV detail_uv; + DetailUV detail_uv = DETAIL_UV_1; - bool deep_parallax; + bool deep_parallax = false; int deep_parallax_min_layers; int deep_parallax_max_layers; - bool heightmap_parallax_flip_tangent; - bool heightmap_parallax_flip_binormal; + bool heightmap_parallax_flip_tangent = false; + bool heightmap_parallax_flip_binormal = false; - bool proximity_fade_enabled; + bool proximity_fade_enabled = false; float proximity_fade_distance; - DistanceFadeMode distance_fade; + DistanceFadeMode distance_fade = DISTANCE_FADE_DISABLED; float distance_fade_max_distance; float distance_fade_min_distance; - BlendMode blend_mode; - BlendMode detail_blend_mode; - DepthDrawMode depth_draw_mode; - CullMode cull_mode; - bool flags[FLAG_MAX]; - SpecularMode specular_mode; - DiffuseMode diffuse_mode; + BlendMode blend_mode = BLEND_MODE_MIX; + BlendMode detail_blend_mode = BLEND_MODE_MIX; + DepthDrawMode depth_draw_mode = DEPTH_DRAW_OPAQUE_ONLY; + CullMode cull_mode = CULL_BACK; + bool flags[FLAG_MAX] = {}; + SpecularMode specular_mode = SPECULAR_SCHLICK_GGX; + DiffuseMode diffuse_mode = DIFFUSE_BURLEY; BillboardMode billboard_mode; - EmissionOperator emission_op; + EmissionOperator emission_op = EMISSION_OP_ADD; TextureChannel metallic_texture_channel; TextureChannel roughness_texture_channel; TextureChannel ao_texture_channel; TextureChannel refraction_texture_channel; - AlphaAntiAliasing alpha_antialiasing_mode; + AlphaAntiAliasing alpha_antialiasing_mode = ALPHA_ANTIALIASING_OFF; - bool features[FEATURE_MAX]; + bool features[FEATURE_MAX] = {}; Ref<Texture2D> textures[TEXTURE_MAX]; @@ -736,7 +741,7 @@ public: static RID get_material_rid_for_2d(bool p_shaded, bool p_transparent, bool p_double_sided, bool p_cut_alpha, bool p_opaque_prepass, bool p_billboard = false, bool p_billboard_y = false); - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; virtual Shader::Mode get_shader_mode() const override; diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index f1c05b8014..1a2b21299a 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -74,7 +74,7 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { } Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<TriangleMesh>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<TriangleMesh>()); int vc = surface_get_array_len(i); Vector<Vector3> vertices = a[ARRAY_VERTEX]; @@ -226,7 +226,7 @@ Ref<Shape3D> Mesh::create_convex_shape() const { for (int i = 0; i < get_surface_count(); i++) { Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<ConvexPolygonShape3D>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<ConvexPolygonShape3D>()); Vector<Vector3> v = a[ARRAY_VERTEX]; vertices.append_array(v); } @@ -266,7 +266,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const { } Array a = surface_get_arrays(i); - ERR_FAIL_COND_V(a.empty(), Ref<ArrayMesh>()); + ERR_FAIL_COND_V(a.is_empty(), Ref<ArrayMesh>()); if (i == 0) { arrays = a; @@ -1095,6 +1095,15 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const { return true; } +void ArrayMesh::reset_state() { + clear_surfaces(); + clear_blend_shapes(); + + aabb = AABB(); + blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; + custom_aabb = AABB(); +} + void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const { if (_is_generated()) { return; @@ -1156,7 +1165,7 @@ void ArrayMesh::add_surface(uint32_t p_format, PrimitiveType p_primitive, const RenderingServer::get_singleton()->mesh_add_surface(mesh, sd); clear_cache(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -1278,7 +1287,6 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material) surfaces.write[p_idx].material = p_material; RenderingServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid()); - _change_notify("material"); emit_changed(); } @@ -1350,7 +1358,7 @@ AABB ArrayMesh::get_custom_aabb() const { return custom_aabb; } -void ArrayMesh::regen_normalmaps() { +void ArrayMesh::regen_normal_maps() { if (surfaces.size() == 0) { return; } @@ -1375,8 +1383,8 @@ bool (*array_mesh_lightmap_unwrap_callback)(float p_texel_size, const float *p_v struct ArrayMeshLightmapSurface { Ref<Material> material; LocalVector<SurfaceTool::Vertex> vertices; - Mesh::PrimitiveType primitive; - uint32_t format; + Mesh::PrimitiveType primitive = Mesh::PrimitiveType::PRIMITIVE_MAX; + uint32_t format = 0; }; Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texel_size) { @@ -1565,6 +1573,19 @@ Error ArrayMesh::lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cach return OK; } +void ArrayMesh::set_shadow_mesh(const Ref<ArrayMesh> &p_mesh) { + shadow_mesh = p_mesh; + if (shadow_mesh.is_valid()) { + RS::get_singleton()->mesh_set_shadow_mesh(mesh, shadow_mesh->get_rid()); + } else { + RS::get_singleton()->mesh_set_shadow_mesh(mesh, RID()); + } +} + +Ref<ArrayMesh> ArrayMesh::get_shadow_mesh() const { + return shadow_mesh; +} + void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("add_blend_shape", "name"), &ArrayMesh::add_blend_shape); ClassDB::bind_method(D_METHOD("get_blend_shape_count"), &ArrayMesh::get_blend_shape_count); @@ -1586,8 +1607,8 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("create_trimesh_shape"), &ArrayMesh::create_trimesh_shape); ClassDB::bind_method(D_METHOD("create_convex_shape"), &ArrayMesh::create_convex_shape); ClassDB::bind_method(D_METHOD("create_outline", "margin"), &ArrayMesh::create_outline); - ClassDB::bind_method(D_METHOD("regen_normalmaps"), &ArrayMesh::regen_normalmaps); - ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normalmaps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); + ClassDB::bind_method(D_METHOD("regen_normal_maps"), &ArrayMesh::regen_normal_maps); + ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normal_maps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("lightmap_unwrap", "transform", "texel_size"), &ArrayMesh::lightmap_unwrap); ClassDB::set_method_flags(get_class_static(), _scs_create("lightmap_unwrap"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ClassDB::bind_method(D_METHOD("get_faces"), &ArrayMesh::get_faces); @@ -1596,6 +1617,9 @@ void ArrayMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb); ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb); + ClassDB::bind_method(D_METHOD("set_shadow_mesh", "mesh"), &ArrayMesh::set_shadow_mesh); + ClassDB::bind_method(D_METHOD("get_shadow_mesh"), &ArrayMesh::get_shadow_mesh); + ClassDB::bind_method(D_METHOD("_set_blend_shape_names", "blend_shape_names"), &ArrayMesh::_set_blend_shape_names); ClassDB::bind_method(D_METHOD("_get_blend_shape_names"), &ArrayMesh::_get_blend_shape_names); @@ -1606,6 +1630,7 @@ void ArrayMesh::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_surfaces", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_surfaces", "_get_surfaces"); ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative"), "set_blend_shape_mode", "get_blend_shape_mode"); ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shadow_mesh", PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh"), "set_shadow_mesh", "get_shadow_mesh"); } void ArrayMesh::reload_from_file() { @@ -1616,13 +1641,12 @@ void ArrayMesh::reload_from_file() { Resource::reload_from_file(); - _change_notify(); + notify_property_list_changed(); } ArrayMesh::ArrayMesh() { //mesh is now created on demand //mesh = RenderingServer::get_singleton()->mesh_create(); - blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; } ArrayMesh::~ArrayMesh() { diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index b7f60bf814..2ce519e644 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -176,23 +176,24 @@ class ArrayMesh : public Mesh { Array _get_surfaces() const; void _set_surfaces(const Array &p_data); + Ref<ArrayMesh> shadow_mesh; private: struct Surface { - uint32_t format; - int array_length; - int index_array_length; - PrimitiveType primitive; + uint32_t format = 0; + int array_length = 0; + int index_array_length = 0; + PrimitiveType primitive = PrimitiveType::PRIMITIVE_MAX; String name; AABB aabb; Ref<Material> material; - bool is_2d; + bool is_2d = false; }; Vector<Surface> surfaces; mutable RID mesh; AABB aabb; - BlendShapeMode blend_shape_mode; + BlendShapeMode blend_shape_mode = BLEND_SHAPE_MODE_RELATIVE; Vector<StringName> blend_shapes; AABB custom_aabb; @@ -206,6 +207,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + static void _bind_methods(); public: @@ -252,13 +255,16 @@ public: AABB get_aabb() const override; virtual RID get_rid() const override; - void regen_normalmaps(); + void regen_normal_maps(); Error lightmap_unwrap(const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); Error lightmap_unwrap_cached(int *&r_cache_data, unsigned int &r_cache_size, bool &r_used_cache, const Transform &p_base_transform = Transform(), float p_texel_size = 0.05); virtual void reload_from_file() override; + void set_shadow_mesh(const Ref<ArrayMesh> &p_mesh); + Ref<ArrayMesh> get_shadow_mesh() const; + ArrayMesh(); ~ArrayMesh(); diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp index a5c360f123..3fb4f8f211 100644 --- a/scene/resources/mesh_data_tool.cpp +++ b/scene/resources/mesh_data_tool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -43,13 +43,35 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf ERR_FAIL_COND_V(p_mesh->surface_get_primitive_type(p_surface) != Mesh::PRIMITIVE_TRIANGLES, ERR_INVALID_PARAMETER); Array arrays = p_mesh->surface_get_arrays(p_surface); - ERR_FAIL_COND_V(arrays.empty(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(arrays.is_empty(), ERR_INVALID_PARAMETER); Vector<Vector3> varray = arrays[Mesh::ARRAY_VERTEX]; int vcount = varray.size(); ERR_FAIL_COND_V(vcount == 0, ERR_INVALID_PARAMETER); + Vector<int> indices; + + if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { + indices = arrays[Mesh::ARRAY_INDEX]; + } else { + //make code simpler + indices.resize(vcount); + int *iw = indices.ptrw(); + for (int i = 0; i < vcount; i++) { + iw[i] = i; + } + } + + int icount = indices.size(); + const int *r = indices.ptr(); + + ERR_FAIL_COND_V(icount == 0, ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(icount % 3, ERR_INVALID_PARAMETER); + for (int i = 0; i < icount; i++) { + ERR_FAIL_INDEX_V(r[i], vcount, ERR_INVALID_PARAMETER); + } + clear(); format = p_mesh->surface_get_format(p_surface); material = p_mesh->surface_get_material(p_surface); @@ -128,22 +150,6 @@ Error MeshDataTool::create_from_surface(const Ref<ArrayMesh> &p_mesh, int p_surf vertices.write[i] = v; } - Vector<int> indices; - - if (arrays[Mesh::ARRAY_INDEX].get_type() != Variant::NIL) { - indices = arrays[Mesh::ARRAY_INDEX]; - } else { - //make code simpler - indices.resize(vcount); - int *iw = indices.ptrw(); - for (int i = 0; i < vcount; i++) { - iw[i] = i; - } - } - - int icount = indices.size(); - const int *r = indices.ptr(); - Map<Point2i, int> edge_indices; for (int i = 0; i < icount; i += 3) { diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h index bf9f0dd25f..f5c8f11437 100644 --- a/scene/resources/mesh_data_tool.h +++ b/scene/resources/mesh_data_tool.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,7 +36,7 @@ class MeshDataTool : public Reference { GDCLASS(MeshDataTool, Reference); - int format; + int format = 0; struct Vertex { Vector3 vertex; Color color; @@ -54,7 +54,7 @@ class MeshDataTool : public Reference { Vector<Vertex> vertices; struct Edge { - int vertex[2]; + int vertex[2] = {}; Vector<int> faces; Variant meta; }; @@ -62,8 +62,8 @@ class MeshDataTool : public Reference { Vector<Edge> edges; struct Face { - int v[3]; - int edges[3]; + int v[3] = {}; + int edges[3] = {}; Variant meta; }; diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index 09b0d4b038..ad90481fbd 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -109,14 +109,14 @@ void MeshLibrary::create_item(int p_item) { ERR_FAIL_COND(p_item < 0); ERR_FAIL_COND(item_map.has(p_item)); item_map[p_item] = Item(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_name(int p_item, const String &p_name) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].name = p_name; emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { @@ -124,25 +124,25 @@ void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { item_map[p_item].mesh = p_mesh; notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].shapes = p_shapes; - _change_notify(); + notify_property_list_changed(); notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].navmesh = p_navmesh; - _change_notify(); + notify_property_list_changed(); notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { @@ -150,14 +150,14 @@ void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_tran item_map[p_item].navmesh_transform = p_transform; notify_change_to_owners(); emit_changed(); - _change_notify(); + notify_property_list_changed(); } void MeshLibrary::set_item_preview(int p_item, const Ref<Texture2D> &p_preview) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map[p_item].preview = p_preview; emit_changed(); - _change_notify(); + notify_property_list_changed(); } String MeshLibrary::get_item_name(int p_item) const { @@ -198,14 +198,14 @@ void MeshLibrary::remove_item(int p_item) { ERR_FAIL_COND_MSG(!item_map.has(p_item), "Requested for nonexistent MeshLibrary item '" + itos(p_item) + "'."); item_map.erase(p_item); notify_change_to_owners(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } void MeshLibrary::clear() { item_map.clear(); notify_change_to_owners(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -264,6 +264,9 @@ Array MeshLibrary::_get_item_shapes(int p_item) const { return ret; } +void MeshLibrary::reset_state() { + clear(); +} void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("create_item", "id"), &MeshLibrary::create_item); ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 0d5fb3005b..1da624c275 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -65,6 +65,7 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; static void _bind_methods(); public: diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp index f71cf383e5..4991887eb3 100644 --- a/scene/resources/multimesh.cpp +++ b/scene/resources/multimesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -217,7 +217,7 @@ Ref<Mesh> MultiMesh::get_mesh() const { void MultiMesh::set_instance_count(int p_count) { ERR_FAIL_COND(p_count < 0); - RenderingServer::get_singleton()->multimesh_allocate(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data); + RenderingServer::get_singleton()->multimesh_allocate_data(multimesh, p_count, RS::MultimeshTransformFormat(transform_format), use_colors, use_custom_data); instance_count = p_count; } @@ -361,11 +361,6 @@ void MultiMesh::_bind_methods() { MultiMesh::MultiMesh() { multimesh = RenderingServer::get_singleton()->multimesh_create(); - use_colors = false; - use_custom_data = false; - transform_format = TRANSFORM_2D; - visible_instance_count = -1; - instance_count = 0; } MultiMesh::~MultiMesh() { diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h index 16f5998a04..ca5c42d47a 100644 --- a/scene/resources/multimesh.h +++ b/scene/resources/multimesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -47,11 +47,11 @@ public: private: Ref<Mesh> mesh; RID multimesh; - TransformFormat transform_format; - bool use_colors; - bool use_custom_data; - int instance_count; - int visible_instance_count; + TransformFormat transform_format = TRANSFORM_2D; + bool use_colors = false; + bool use_custom_data = false; + int instance_count = 0; + int visible_instance_count = -1; protected: static void _bind_methods(); diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index e815da5d45..8c12f59a00 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -31,6 +31,8 @@ #include "navigation_mesh.h" void NavigationMesh::create_from_mesh(const Ref<Mesh> &p_mesh) { + ERR_FAIL_COND(p_mesh.is_null()); + vertices = Vector<Vector3>(); clear_polygons(); @@ -74,7 +76,7 @@ int NavigationMesh::get_sample_partition_type() const { void NavigationMesh::set_parsed_geometry_type(int p_value) { ERR_FAIL_COND(p_value >= PARSED_GEOMETRY_MAX); parsed_geometry_type = static_cast<ParsedGeometryType>(p_value); - _change_notify(); + notify_property_list_changed(); } int NavigationMesh::get_parsed_geometry_type() const { @@ -106,7 +108,7 @@ bool NavigationMesh::get_collision_mask_bit(int p_bit) const { void NavigationMesh::set_source_geometry_mode(int p_geometry_mode) { ERR_FAIL_INDEX(p_geometry_mode, SOURCE_GEOMETRY_MAX); source_geometry_mode = static_cast<SourceGeometryMode>(p_geometry_mode); - _change_notify(); + notify_property_list_changed(); } int NavigationMesh::get_source_geometry_mode() const { @@ -251,7 +253,7 @@ bool NavigationMesh::get_filter_walkable_low_height_spans() const { void NavigationMesh::set_vertices(const Vector<Vector3> &p_vertices) { vertices = p_vertices; - _change_notify(); + notify_property_list_changed(); } Vector<Vector3> NavigationMesh::get_vertices() const { @@ -263,7 +265,7 @@ void NavigationMesh::_set_polygons(const Array &p_array) { for (int i = 0; i < p_array.size(); i++) { polygons.write[i].indices = p_array[i]; } - _change_notify(); + notify_property_list_changed(); } Array NavigationMesh::_get_polygons() const { @@ -280,7 +282,7 @@ void NavigationMesh::add_polygon(const Vector<int> &p_polygon) { Polygon polygon; polygon.indices = p_polygon; polygons.push_back(polygon); - _change_notify(); + notify_property_list_changed(); } int NavigationMesh::get_polygon_count() const { @@ -510,27 +512,4 @@ void NavigationMesh::_validate_property(PropertyInfo &property) const { } } -NavigationMesh::NavigationMesh() { - cell_size = 0.3f; - cell_height = 0.2f; - agent_height = 2.0f; - agent_radius = 0.6f; - agent_max_climb = 0.9f; - agent_max_slope = 45.0f; - region_min_size = 8.0f; - region_merge_size = 20.0f; - edge_max_length = 12.0f; - edge_max_error = 1.3f; - verts_per_poly = 6.0f; - detail_sample_distance = 6.0f; - detail_sample_max_error = 1.0f; - - partition_type = SAMPLE_PARTITION_WATERSHED; - parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; - collision_mask = 0xFFFFFFFF; - source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; - source_group_name = "navmesh"; - filter_low_hanging_obstacles = false; - filter_ledge_spans = false; - filter_walkable_low_height_spans = false; -} +NavigationMesh::NavigationMesh() {} diff --git a/scene/resources/navigation_mesh.h b/scene/resources/navigation_mesh.h index b94f4408e1..966221c7c6 100644 --- a/scene/resources/navigation_mesh.h +++ b/scene/resources/navigation_mesh.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -82,30 +82,30 @@ public: }; protected: - float cell_size; - float cell_height; - float agent_height; - float agent_radius; - float agent_max_climb; - float agent_max_slope; - float region_min_size; - float region_merge_size; - float edge_max_length; - float edge_max_error; - float verts_per_poly; - float detail_sample_distance; - float detail_sample_max_error; - - SamplePartitionType partition_type; - ParsedGeometryType parsed_geometry_type; - uint32_t collision_mask; - - SourceGeometryMode source_geometry_mode; - StringName source_group_name; - - bool filter_low_hanging_obstacles; - bool filter_ledge_spans; - bool filter_walkable_low_height_spans; + float cell_size = 0.3f; + float cell_height = 0.2f; + float agent_height = 2.0f; + float agent_radius = 0.6f; + float agent_max_climb = 0.9f; + float agent_max_slope = 45.0f; + float region_min_size = 8.0f; + float region_merge_size = 20.0f; + float edge_max_length = 12.0f; + float edge_max_error = 1.3f; + float verts_per_poly = 6.0f; + float detail_sample_distance = 6.0f; + float detail_sample_max_error = 1.0f; + + SamplePartitionType partition_type = SAMPLE_PARTITION_WATERSHED; + ParsedGeometryType parsed_geometry_type = PARSED_GEOMETRY_MESH_INSTANCES; + uint32_t collision_mask = 0xFFFFFFFF; + + SourceGeometryMode source_geometry_mode = SOURCE_GEOMETRY_NAVMESH_CHILDREN; + StringName source_group_name = "navmesh"; + + bool filter_low_hanging_obstacles = false; + bool filter_ledge_spans = false; + bool filter_walkable_low_height_spans = false; public: // Recast settings diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 09674f3465..ab8a4b7934 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -80,7 +80,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const { Node **ret_nodes = (Node **)alloca(sizeof(Node *) * nc); - bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.empty(); + bool gen_node_path_cache = p_edit_state != GEN_EDIT_STATE_DISABLED && node_path_cache.is_empty(); Map<Ref<Resource>, Ref<Resource>> resources_local_to_scene; @@ -147,15 +147,20 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } #endif } - } else if (ClassDB::is_class_enabled(snames[n.type])) { - //node belongs to this scene and must be created - Object *obj = ClassDB::instance(snames[n.type]); + } else { + Object *obj = nullptr; + + if (ClassDB::is_class_enabled(snames[n.type])) { + //node belongs to this scene and must be created + obj = ClassDB::instance(snames[n.type]); + } + if (!Object::cast_to<Node>(obj)) { if (obj) { memdelete(obj); obj = nullptr; } - WARN_PRINT(String("Warning node of type " + snames[n.type].operator String() + " does not exist.").ascii().get_data()); + WARN_PRINT(vformat("Node %s of type %s cannot be created. A placeholder will be created instead.", snames[n.name], snames[n.type]).ascii().get_data()); if (n.parent >= 0 && n.parent < nc && ret_nodes[n.parent]) { if (Object::cast_to<Node3D>(ret_nodes[n.parent])) { obj = memnew(Node3D); @@ -172,10 +177,6 @@ Node *SceneState::instance(GenEditState p_edit_state) const { } node = Object::cast_to<Node>(obj); - - } else { - //print_line("Class is disabled for: " + itos(n.type)); - //print_line("name: " + String(snames[n.type])); } if (node) { @@ -469,6 +470,11 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map p_node->get_property_list(&plist); StringName type = p_node->get_class(); + Ref<Script> script = p_node->get_script(); + if (script.is_valid()) { + script->update_exports(); + } + for (List<PropertyInfo>::Element *E = plist.front(); E; E = E->next()) { if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { continue; @@ -484,7 +490,6 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value)); } - Ref<Script> script = p_node->get_script(); if (!isdefault && script.is_valid() && script->get_property_default_value(name, default_value)) { isdefault = bool(Variant::evaluate(Variant::OP_EQUAL, value, default_value)); } @@ -603,7 +608,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map // Save the right type. If this node was created by an instance // then flag that the node should not be created but reused - if (pack_state_stack.empty()) { + if (pack_state_stack.is_empty()) { //this node is not part of an instancing process, so save the type nd.type = _nm_get_string(p_node->get_class(), name_map); } else { @@ -1349,7 +1354,7 @@ NodePath SceneState::get_node_path(int p_idx, bool p_for_parent) const { sub_path.insert(0, base_path.get_name(i)); } - if (sub_path.empty()) { + if (sub_path.is_empty()) { return NodePath("."); } @@ -1589,8 +1594,6 @@ void SceneState::_bind_methods() { } SceneState::SceneState() { - base_scene_idx = -1; - last_modified_time = 0; } //////////////// @@ -1663,6 +1666,9 @@ void PackedScene::set_path(const String &p_path, bool p_take_over) { Resource::set_path(p_path, p_take_over); } +void PackedScene::reset_state() { + clear(); +} void PackedScene::_bind_methods() { ClassDB::bind_method(D_METHOD("pack", "path"), &PackedScene::pack); ClassDB::bind_method(D_METHOD("instance", "edit_state"), &PackedScene::instance, DEFVAL(GEN_EDIT_STATE_DISABLED)); diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index fce3891507..78a0aeaa9a 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,7 +44,7 @@ class SceneState : public Reference { mutable HashMap<NodePath, int> node_path_cache; mutable Map<int, int> base_scene_node_remap; - int base_scene_idx; + int base_scene_idx = -1; enum { NO_PARENT_SAVED = 0x7FFFFFFF, @@ -53,16 +53,16 @@ class SceneState : public Reference { }; struct NodeData { - int parent; - int owner; - int type; - int name; - int instance; - int index; + int parent = 0; + int owner = 0; + int type = 0; + int name = 0; + int instance = 0; + int index = 0; struct Property { - int name; - int value; + int name = 0; + int value = 0; }; Vector<Property> properties; @@ -71,18 +71,17 @@ class SceneState : public Reference { struct PackState { Ref<SceneState> state; - int node; - PackState() { node = -1; } + int node = -1; }; Vector<NodeData> nodes; struct ConnectionData { - int from; - int to; - int signal; - int method; - int flags; + int from = 0; + int to = 0; + int signal = 0; + int method = 0; + int flags = 0; Vector<int> binds; }; @@ -93,7 +92,7 @@ class SceneState : public Reference { String path; - uint64_t last_modified_time; + uint64_t last_modified_time = 0; _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const; @@ -201,6 +200,7 @@ class PackedScene : public Resource { protected: virtual bool editor_can_reload_from_file() override { return false; } // this is handled by editor better static void _bind_methods(); + virtual void reset_state() override; public: enum GenEditState { diff --git a/scene/resources/particles_material.cpp b/scene/resources/particles_material.cpp index e2f96c54cb..195ce070a7 100644 --- a/scene/resources/particles_material.cpp +++ b/scene/resources/particles_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -305,6 +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 += " float tv = 0.0;\n"; code += " if (RESTART) {\n"; if (tex_parameters[PARAM_ANGLE].is_valid()) { @@ -339,14 +340,21 @@ void ParticlesMaterial::_update_shader() { //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 += " vec3 spread_direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n"; + code += " vec3 direction_nrm = normalize(direction);\n"; + code += " // rotate spread to direction\n"; + code += " vec3 binormal = cross(vec3(0.0, 1.0, 0.0), direction_nrm);\n"; + code += " if (length(binormal) < 0.0001) {\n"; + code += " // direction is parallel to Y. Choose Z as the binormal.\n"; + code += " binormal = vec3(0.0, 0.0, 1.0);\n"; + code += " }\n"; + code += " binormal = normalize(binormal);\n"; + code += " vec3 normal = cross(binormal, direction_nrm);\n"; + code += " spread_direction = binormal * spread_direction.x + normal * spread_direction.y + direction_nrm * spread_direction.z;\n"; + code += " VELOCITY = spread_direction * initial_linear_velocity * mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n"; } code += " }\n"; @@ -407,64 +415,65 @@ void ParticlesMaterial::_update_shader() { code += " } else {\n"; code += " CUSTOM.y += DELTA / LIFETIME;\n"; + code += " tv = CUSTOM.y / CUSTOM.w;\n"; if (tex_parameters[PARAM_INITIAL_LINEAR_VELOCITY].is_valid()) { - code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_linear_velocity = textureLod(linear_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_linear_velocity = 0.0;\n"; } if (particle_flags[PARTICLE_FLAG_DISABLE_Z]) { if (tex_parameters[PARAM_ORBIT_VELOCITY].is_valid()) { - code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_orbit_velocity = textureLod(orbit_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_orbit_velocity = 0.0;\n"; } } if (tex_parameters[PARAM_ANGULAR_VELOCITY].is_valid()) { - code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_angular_velocity = textureLod(angular_velocity_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_angular_velocity = 0.0;\n"; } if (tex_parameters[PARAM_LINEAR_ACCEL].is_valid()) { - code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_linear_accel = textureLod(linear_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_linear_accel = 0.0;\n"; } if (tex_parameters[PARAM_RADIAL_ACCEL].is_valid()) { - code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_radial_accel = textureLod(radial_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_radial_accel = 0.0;\n"; } if (tex_parameters[PARAM_TANGENTIAL_ACCEL].is_valid()) { - code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_tangent_accel = textureLod(tangent_accel_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_tangent_accel = 0.0;\n"; } if (tex_parameters[PARAM_DAMPING].is_valid()) { - code += " float tex_damping = textureLod(damping_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_damping = textureLod(damping_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_damping = 0.0;\n"; } if (tex_parameters[PARAM_ANGLE].is_valid()) { - code += " float tex_angle = textureLod(angle_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_angle = textureLod(angle_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_angle = 0.0;\n"; } if (tex_parameters[PARAM_ANIM_SPEED].is_valid()) { - code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_anim_speed = textureLod(anim_speed_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_anim_speed = 0.0;\n"; } if (tex_parameters[PARAM_ANIM_OFFSET].is_valid()) { - code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_anim_offset = textureLod(anim_offset_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_anim_offset = 0.0;\n"; } @@ -526,13 +535,13 @@ void ParticlesMaterial::_update_shader() { // apply color // apply hue rotation if (tex_parameters[PARAM_SCALE].is_valid()) { - code += " float tex_scale = textureLod(scale_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_scale = textureLod(scale_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_scale = 1.0;\n"; } if (tex_parameters[PARAM_HUE_VARIATION].is_valid()) { - code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(CUSTOM.y, 0.0), 0.0).r;\n"; + code += " float tex_hue_variation = textureLod(hue_variation_texture, vec2(tv, 0.0), 0.0).r;\n"; } else { code += " float tex_hue_variation = 0.0;\n"; } @@ -553,7 +562,7 @@ void ParticlesMaterial::_update_shader() { code += " vec4(1.250, -1.050, -0.203, 0.0),\n"; code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n"; if (color_ramp.is_valid()) { - code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(CUSTOM.y, 0.0), 0.0);\n"; + code += " COLOR = hue_rot_mat * textureLod(color_ramp, vec2(tv, 0.0), 0.0);\n"; } else { code += " COLOR = hue_rot_mat * color_value;\n"; } @@ -646,7 +655,7 @@ void ParticlesMaterial::_update_shader() { 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 += " emit_subparticle(TRANSFORM,VELOCITY,vec4(0.0),vec4(0.0),flags);\n"; code += " }"; } @@ -909,7 +918,7 @@ void ParticlesMaterial::set_color_ramp(const Ref<Texture2D> &p_texture) { color_ramp = p_texture; RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->color_ramp, p_texture); _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } Ref<Texture2D> ParticlesMaterial::get_color_ramp() const { @@ -921,7 +930,7 @@ void ParticlesMaterial::set_particle_flag(ParticleFlags p_particle_flag, bool p_ particle_flags[p_particle_flag] = p_enable; _queue_shader_change(); if (p_particle_flag == PARTICLE_FLAG_DISABLE_Z) { - _change_notify(); + notify_property_list_changed(); } } @@ -933,7 +942,7 @@ bool ParticlesMaterial::get_particle_flag(ParticleFlags p_particle_flag) const { void ParticlesMaterial::set_emission_shape(EmissionShape p_shape) { ERR_FAIL_INDEX(p_shape, EMISSION_SHAPE_MAX); emission_shape = p_shape; - _change_notify(); + notify_property_list_changed(); _queue_shader_change(); } @@ -1064,7 +1073,7 @@ void ParticlesMaterial::_validate_property(PropertyInfo &property) const { void ParticlesMaterial::set_sub_emitter_mode(SubEmitterMode p_sub_emitter_mode) { sub_emitter_mode = p_sub_emitter_mode; _queue_shader_change(); - _change_notify(); + notify_property_list_changed(); } ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() const { @@ -1073,7 +1082,7 @@ ParticlesMaterial::SubEmitterMode ParticlesMaterial::get_sub_emitter_mode() cons 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 + RenderingServer::get_singleton()->material_set_param(_get_material(), shader_names->sub_emitter_frequency, 1.0 / p_frequency); //pass delta instead of frequency, since its easier to compute } float ParticlesMaterial::get_sub_emitter_frequency() const { return sub_emitter_frequency; @@ -1368,7 +1377,6 @@ ParticlesMaterial::ParticlesMaterial() : set_emission_box_extents(Vector3(1, 1, 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); @@ -1391,7 +1399,6 @@ ParticlesMaterial::ParticlesMaterial() : set_color(Color(1, 1, 1, 1)); - current_key.key = 0; current_key.invalid_key = 1; _queue_shader_change(); diff --git a/scene/resources/particles_material.h b/scene/resources/particles_material.h index 7e8f05b706..3f874bd68c 100644 --- a/scene/resources/particles_material.h +++ b/scene/resources/particles_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -100,7 +100,7 @@ private: uint32_t collision_scale : 1; }; - uint32_t key; + uint32_t key = 0; bool operator<(const MaterialKey &p_key) const { return key < p_key.key; @@ -109,7 +109,7 @@ private: struct ShaderData { RID shader; - int users; + int users = 0; }; static Map<MaterialKey, ShaderData> shader_map; @@ -235,7 +235,7 @@ private: Ref<Texture2D> emission_point_texture; Ref<Texture2D> emission_normal_texture; Ref<Texture2D> emission_color_texture; - int emission_point_count; + int emission_point_count = 1; bool anim_loop; @@ -340,7 +340,7 @@ public: void set_sub_emitter_keep_velocity(bool p_enable); bool get_sub_emitter_keep_velocity() const; - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; virtual Shader::Mode get_shader_mode() const override; diff --git a/scene/resources/physics_material.cpp b/scene/resources/physics_material.cpp index 59bf8c0e13..d65b0c8927 100644 --- a/scene/resources/physics_material.cpp +++ b/scene/resources/physics_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/physics_material.h b/scene/resources/physics_material.h index e9222ffa1b..d302800823 100644 --- a/scene/resources/physics_material.h +++ b/scene/resources/physics_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,9 +39,9 @@ class PhysicsMaterial : public Resource { OBJ_SAVE_TYPE(PhysicsMaterial); RES_BASE_EXTENSION("phymat"); - real_t friction = 1; + real_t friction = 1.0; bool rough = false; - real_t bounce = 0; + real_t bounce = 0.0; bool absorbent = false; protected: diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index df98d4cfd4..536318ed16 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -77,7 +77,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> outside_point.x += 20.451 + Math::randf() * 10.2039; outside_point.y += 21.193 + Math::randf() * 12.5412; - //insert edges (which are also connetions) + //insert edges (which are also connections) for (int i = 0; i < p_connections.size(); i += 2) { Edge e(p_connections[i], p_connections[i + 1]); @@ -335,7 +335,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector //oh this was visited already, can we win the cost? if (p.distance > distance) { - p.prev = least_cost_point; //reasign previous + p.prev = least_cost_point; //reassign previous p.distance = distance; } } else { diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h index 44a97b4294..2f3cb634fb 100644 --- a/scene/resources/polygon_path_finder.h +++ b/scene/resources/polygon_path_finder.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,13 +39,13 @@ class PolygonPathFinder : public Resource { struct Point { Vector2 pos; Set<int> connections; - float distance; - float penalty; - int prev; + float distance = 0.0; + float penalty = 0.0; + int prev = 0; }; struct Edge { - int points[2]; + int points[2] = {}; _FORCE_INLINE_ bool operator<(const Edge &p_edge) const { if (points[0] == p_edge.points[0]) { diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index 06e181cb99..ba6c4591c9 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -214,7 +214,7 @@ void PrimitiveMesh::set_material(const Ref<Material> &p_material) { if (!pending_request) { // just apply it, else it'll happen when _update is called. RenderingServer::get_singleton()->mesh_surface_set_material(mesh, 0, material.is_null() ? RID() : material->get_rid()); - _change_notify(); + notify_property_list_changed(); emit_changed(); }; } @@ -247,18 +247,7 @@ bool PrimitiveMesh::get_flip_faces() const { } PrimitiveMesh::PrimitiveMesh() { - flip_faces = false; - // defaults mesh = RenderingServer::get_singleton()->mesh_create(); - - // assume primitive triangles as the type, correct for all but one and it will change this :) - primitive_type = Mesh::PRIMITIVE_TRIANGLES; - - // make sure we do an update after we've finished constructing our object - pending_request = true; - - array_len = 0; - index_array_len = 0; } PrimitiveMesh::~PrimitiveMesh() { @@ -304,8 +293,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = -sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, 0.5 * mid_height, 0.0)); @@ -343,8 +332,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = -sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = -sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius, y, -z * radius); points.push_back(p); @@ -383,8 +372,8 @@ void CapsuleMesh::_create_mesh_array(Array &p_arr) const { float u2 = i; u2 /= radial_segments; - x = -sin(u2 * (Math_PI * 2.0)); - z = cos(u2 * (Math_PI * 2.0)); + x = -sin(u2 * Math_TAU); + z = cos(u2 * Math_TAU); Vector3 p = Vector3(x * radius * w, y, -z * radius * w); points.push_back(p + Vector3(0.0, -0.5 * mid_height, 0.0)); @@ -468,13 +457,7 @@ int CapsuleMesh::get_rings() const { return rings; } -CapsuleMesh::CapsuleMesh() { - // defaults - radius = 1.0; - mid_height = 1.0; - radial_segments = 64; - rings = 8; -} +CapsuleMesh::CapsuleMesh() {} /** BoxMesh @@ -725,13 +708,7 @@ int BoxMesh::get_subdivide_depth() const { return subdivide_d; } -BoxMesh::BoxMesh() { - // defaults - size = Vector3(2.0, 2.0, 2.0); - subdivide_w = 0; - subdivide_h = 0; - subdivide_d = 0; -} +BoxMesh::BoxMesh() {} /** CylinderMesh @@ -769,8 +746,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { u = i; u /= radial_segments; - x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); Vector3 p = Vector3(x * radius, y, z * radius); points.push_back(p); @@ -809,8 +786,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_segments; - x = sin(r * (Math_PI * 2.0)); - z = cos(r * (Math_PI * 2.0)); + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); u = ((x + 1.0) * 0.25); v = 0.5 + ((z + 1.0) * 0.25); @@ -845,8 +822,8 @@ void CylinderMesh::_create_mesh_array(Array &p_arr) const { float r = i; r /= radial_segments; - x = sin(r * (Math_PI * 2.0)); - z = cos(r * (Math_PI * 2.0)); + x = sin(r * Math_TAU); + z = cos(r * Math_TAU); u = 0.5 + ((x + 1.0) * 0.25); v = 1.0 - ((z + 1.0) * 0.25); @@ -938,14 +915,7 @@ int CylinderMesh::get_rings() const { return rings; } -CylinderMesh::CylinderMesh() { - // defaults - top_radius = 1.0; - bottom_radius = 1.0; - height = 2.0; - radial_segments = 64; - rings = 4; -} +CylinderMesh::CylinderMesh() {} /** PlaneMesh @@ -1053,12 +1023,7 @@ int PlaneMesh::get_subdivide_depth() const { return subdivide_d; } -PlaneMesh::PlaneMesh() { - // defaults - size = Size2(2.0, 2.0); - subdivide_w = 0; - subdivide_d = 0; -} +PlaneMesh::PlaneMesh() {} /** PrismMesh @@ -1338,14 +1303,7 @@ int PrismMesh::get_subdivide_depth() const { return subdivide_d; } -PrismMesh::PrismMesh() { - // defaults - left_to_right = 0.5; - size = Vector3(2.0, 2.0, 2.0); - subdivide_w = 0; - subdivide_h = 0; - subdivide_d = 0; -} +PrismMesh::PrismMesh() {} /** QuadMesh @@ -1409,7 +1367,6 @@ void QuadMesh::_bind_methods() { QuadMesh::QuadMesh() { primitive_type = PRIMITIVE_TRIANGLES; - size = Size2(1.0, 1.0); } void QuadMesh::set_size(const Size2 &p_size) { @@ -1458,8 +1415,8 @@ void SphereMesh::_create_mesh_array(Array &p_arr) const { float u = i; u /= radial_segments; - x = sin(u * (Math_PI * 2.0)); - z = cos(u * (Math_PI * 2.0)); + x = sin(u * Math_TAU); + z = cos(u * Math_TAU); if (is_hemisphere && y < 0.0) { points.push_back(Vector3(x * radius * w, 0.0, z * radius * w)); @@ -1561,14 +1518,7 @@ bool SphereMesh::get_is_hemisphere() const { return is_hemisphere; } -SphereMesh::SphereMesh() { - // defaults - radius = 1.0; - height = 2.0; - radial_segments = 64; - rings = 32; - is_hemisphere = false; -} +SphereMesh::SphereMesh() {} /** PointMesh diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h index 02aea9c5c8..bb3df9d10e 100644 --- a/scene/resources/primitive_meshes.h +++ b/scene/resources/primitive_meshes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -49,17 +49,19 @@ private: mutable AABB aabb; AABB custom_aabb; - mutable int array_len; - mutable int index_array_len; + mutable int array_len = 0; + mutable int index_array_len = 0; Ref<Material> material; - bool flip_faces; + bool flip_faces = false; - mutable bool pending_request; + // make sure we do an update after we've finished constructing our object + mutable bool pending_request = true; void _update() const; protected: - Mesh::PrimitiveType primitive_type; + // assume primitive triangles as the type, correct for all but one and it will change this :) + Mesh::PrimitiveType primitive_type = Mesh::PRIMITIVE_TRIANGLES; static void _bind_methods(); @@ -104,10 +106,10 @@ class CapsuleMesh : public PrimitiveMesh { GDCLASS(CapsuleMesh, PrimitiveMesh); private: - float radius; - float mid_height; - int radial_segments; - int rings; + float radius = 1.0; + float mid_height = 1.0; + int radial_segments = 64; + int rings = 8; protected: static void _bind_methods(); @@ -136,10 +138,10 @@ class BoxMesh : public PrimitiveMesh { GDCLASS(BoxMesh, PrimitiveMesh); private: - Vector3 size; - int subdivide_w; - int subdivide_h; - int subdivide_d; + Vector3 size = Vector3(2.0, 2.0, 2.0); + int subdivide_w = 0; + int subdivide_h = 0; + int subdivide_d = 0; protected: static void _bind_methods(); @@ -169,11 +171,11 @@ class CylinderMesh : public PrimitiveMesh { GDCLASS(CylinderMesh, PrimitiveMesh); private: - float top_radius; - float bottom_radius; - float height; - int radial_segments; - int rings; + float top_radius = 1.0; + float bottom_radius = 1.0; + float height = 2.0; + int radial_segments = 64; + int rings = 4; protected: static void _bind_methods(); @@ -205,9 +207,9 @@ class PlaneMesh : public PrimitiveMesh { GDCLASS(PlaneMesh, PrimitiveMesh); private: - Size2 size; - int subdivide_w; - int subdivide_d; + Size2 size = Size2(2.0, 2.0); + int subdivide_w = 0; + int subdivide_d = 0; protected: static void _bind_methods(); @@ -233,11 +235,11 @@ class PrismMesh : public PrimitiveMesh { GDCLASS(PrismMesh, PrimitiveMesh); private: - float left_to_right; - Vector3 size; - int subdivide_w; - int subdivide_h; - int subdivide_d; + float left_to_right = 0.5; + Vector3 size = Vector3(2.0, 2.0, 2.0); + int subdivide_w = 0; + int subdivide_h = 0; + int subdivide_d = 0; protected: static void _bind_methods(); @@ -270,7 +272,7 @@ class QuadMesh : public PrimitiveMesh { GDCLASS(QuadMesh, PrimitiveMesh); private: - Size2 size; + Size2 size = Size2(1.0, 1.0); protected: static void _bind_methods(); @@ -290,11 +292,11 @@ class SphereMesh : public PrimitiveMesh { GDCLASS(SphereMesh, PrimitiveMesh); private: - float radius; - float height; - int radial_segments; - int rings; - bool is_hemisphere; + float radius = 1.0; + float height = 2.0; + int radial_segments = 64; + int rings = 32; + bool is_hemisphere = false; protected: static void _bind_methods(); diff --git a/scene/resources/ray_shape_2d.cpp b/scene/resources/ray_shape_2d.cpp index 67c4f84749..fb8f4b9985 100644 --- a/scene/resources/ray_shape_2d.cpp +++ b/scene/resources/ray_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -42,17 +42,33 @@ void RayShape2D::_update_shape() { } void RayShape2D::draw(const RID &p_to_rid, const Color &p_color) { - Vector2 tip = Vector2(0, get_length()); - RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), tip, p_color, 3); + const Vector2 target_position = Vector2(0, get_length()); + + const float max_arrow_size = 6; + const float line_width = 1.4; + bool no_line = target_position.length() < line_width; + float arrow_size = CLAMP(target_position.length() * 2 / 3, line_width, max_arrow_size); + + if (no_line) { + arrow_size = target_position.length(); + } else { + RS::get_singleton()->canvas_item_add_line(p_to_rid, Vector2(), target_position - target_position.normalized() * arrow_size, p_color, line_width); + } + + Transform2D xf; + xf.rotate(target_position.angle()); + xf.translate(Vector2(no_line ? 0 : target_position.length() - arrow_size, 0)); + Vector<Vector2> pts; - float tsize = 4; - pts.push_back(tip + Vector2(0, tsize)); - pts.push_back(tip + Vector2(Math_SQRT12 * tsize, 0)); - pts.push_back(tip + Vector2(-Math_SQRT12 * tsize, 0)); + pts.push_back(xf.xform(Vector2(arrow_size, 0))); + pts.push_back(xf.xform(Vector2(0, 0.5 * arrow_size))); + pts.push_back(xf.xform(Vector2(0, -0.5 * arrow_size))); + Vector<Color> cols; for (int i = 0; i < 3; i++) { cols.push_back(p_color); } + RS::get_singleton()->canvas_item_add_primitive(p_to_rid, pts, cols, Vector<Point2>(), RID()); } @@ -99,7 +115,5 @@ bool RayShape2D::get_slips_on_slope() const { RayShape2D::RayShape2D() : Shape2D(PhysicsServer2D::get_singleton()->ray_shape_create()) { - length = 20; - slips_on_slope = false; _update_shape(); } diff --git a/scene/resources/ray_shape_2d.h b/scene/resources/ray_shape_2d.h index c8202ca16c..56ecfa2722 100644 --- a/scene/resources/ray_shape_2d.h +++ b/scene/resources/ray_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,8 +36,8 @@ class RayShape2D : public Shape2D { GDCLASS(RayShape2D, Shape2D); - real_t length; - bool slips_on_slope; + real_t length = 20.0; + bool slips_on_slope = false; void _update_shape(); diff --git a/scene/resources/ray_shape_3d.cpp b/scene/resources/ray_shape_3d.cpp index 1705fb0f55..5446b4daab 100644 --- a/scene/resources/ray_shape_3d.cpp +++ b/scene/resources/ray_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -56,7 +56,6 @@ void RayShape3D::set_length(float p_length) { length = p_length; _update_shape(); notify_change_to_owners(); - _change_notify("length"); } float RayShape3D::get_length() const { @@ -67,7 +66,6 @@ void RayShape3D::set_slips_on_slope(bool p_active) { slips_on_slope = p_active; _update_shape(); notify_change_to_owners(); - _change_notify("slips_on_slope"); } bool RayShape3D::get_slips_on_slope() const { @@ -87,12 +85,7 @@ void RayShape3D::_bind_methods() { RayShape3D::RayShape3D() : Shape3D(PhysicsServer3D::get_singleton()->shape_create(PhysicsServer3D::SHAPE_RAY)) { - length = 1.0; - slips_on_slope = false; - /* Code copied from setters to prevent the use of uninitialized variables */ _update_shape(); notify_change_to_owners(); - _change_notify("length"); - _change_notify("slips_on_slope"); } diff --git a/scene/resources/ray_shape_3d.h b/scene/resources/ray_shape_3d.h index a1a6702564..2da6311321 100644 --- a/scene/resources/ray_shape_3d.h +++ b/scene/resources/ray_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,8 +34,8 @@ class RayShape3D : public Shape3D { GDCLASS(RayShape3D, Shape3D); - float length; - bool slips_on_slope; + float length = 1.0; + bool slips_on_slope = false; protected: static void _bind_methods(); diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 949fddf2e7..dc4c6dc2d7 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,40 +33,58 @@ #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" void RectangleShape2D::_update_shape() { - PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), extents); + PhysicsServer2D::get_singleton()->shape_set_data(get_rid(), size * 0.5); emit_changed(); } -void RectangleShape2D::set_extents(const Vector2 &p_extents) { - extents = p_extents; +void RectangleShape2D::set_size(const Vector2 &p_size) { + size = p_size; _update_shape(); } -Vector2 RectangleShape2D::get_extents() const { - return extents; +Vector2 RectangleShape2D::get_size() const { + return size; } void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) { - RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-extents, extents * 2.0), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_to_rid, Rect2(-size * 0.5, size), p_color); + if (is_collision_outline_enabled()) { + // Draw an outlined rectangle to make individual shapes easier to distinguish. + Vector<Vector2> stroke_points; + stroke_points.resize(5); + stroke_points.write[0] = -size * 0.5; + stroke_points.write[1] = Vector2(size.x, -size.y) * 0.5; + stroke_points.write[2] = size * 0.5; + stroke_points.write[3] = Vector2(-size.x, size.y) * 0.5; + stroke_points.write[4] = -size * 0.5; + + Vector<Color> stroke_colors; + stroke_colors.resize(5); + for (int i = 0; i < 5; i++) { + stroke_colors.write[i] = (p_color); + } + + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors); + } } Rect2 RectangleShape2D::get_rect() const { - return Rect2(-extents, extents * 2.0); + return Rect2(-size * 0.5, size); } real_t RectangleShape2D::get_enclosing_radius() const { - return extents.length(); + return size.length() / 2; } void RectangleShape2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_extents", "extents"), &RectangleShape2D::set_extents); - ClassDB::bind_method(D_METHOD("get_extents"), &RectangleShape2D::get_extents); + ClassDB::bind_method(D_METHOD("set_size", "size"), &RectangleShape2D::set_size); + ClassDB::bind_method(D_METHOD("get_size"), &RectangleShape2D::get_size); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); } RectangleShape2D::RectangleShape2D() : Shape2D(PhysicsServer2D::get_singleton()->rectangle_shape_create()) { - extents = Vector2(10, 10); + size = Vector2(20, 20); _update_shape(); } diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index 6efa7ab9c8..8d747c86af 100644 --- a/scene/resources/rectangle_shape_2d.h +++ b/scene/resources/rectangle_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -36,15 +36,15 @@ class RectangleShape2D : public Shape2D { GDCLASS(RectangleShape2D, Shape2D); - Vector2 extents; + Vector2 size; void _update_shape(); protected: static void _bind_methods(); public: - void set_extents(const Vector2 &p_extents); - Vector2 get_extents() const; + void set_size(const Vector2 &p_size); + Vector2 get_size() const; virtual void draw(const RID &p_to_rid, const Color &p_color) override; virtual Rect2 get_rect() const override; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 58645dbe65..f2751b7604 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -114,23 +114,8 @@ Error ResourceLoaderText::_parse_sub_resource(VariantParser::Stream *p_stream, R } int index = token.value; - - if (use_nocache) { - r_res = int_resources[index]; - } else { - String path = local_path + "::" + itos(index); - - if (!ignore_resource_parsing) { - if (!ResourceCache::has(path)) { - r_err_str = "Can't load cached sub-resource: " + path; - return ERR_PARSE_ERROR; - } - - r_res = RES(ResourceCache::get(path)); - } else { - r_res = RES(); - } - } + ERR_FAIL_COND_V(!int_resources.has(index), ERR_INVALID_PARAMETER); + r_res = int_resources[index]; VariantParser::get_token(p_stream, token, line, r_err_str); if (token.type != VariantParser::TK_PARENTHESIS_CLOSE) { @@ -440,7 +425,7 @@ Error ResourceLoaderText::load() { er.type = type; if (use_sub_threads) { - Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, local_path); + Error err = ResourceLoader::load_threaded_request(path, type, use_sub_threads, ResourceFormatLoader::CACHE_MODE_REUSE, local_path); if (err != OK) { if (ResourceLoader::get_abort_on_missing_resources()) { @@ -517,29 +502,44 @@ Error ResourceLoaderText::load() { //bool exists=ResourceCache::has(path); Ref<Resource> res; + bool do_assign = false; - if (use_nocache || !ResourceCache::has(path)) { //only if it doesn't exist - - Object *obj = ClassDB::instance(type); - if (!obj) { - error_text += "Can't create sub resource of type: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(path)) { + //reuse existing + Resource *r = ResourceCache::get(path); + if (r && r->get_class() == type) { + res = Ref<Resource>(r); + res->reset_state(); + do_assign = true; } + } - Resource *r = Object::cast_to<Resource>(obj); - if (!r) { - error_text += "Can't create sub resource of type, because not a resource: " + type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } + if (res.is_null()) { //not reuse + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && ResourceCache::has(path)) { //only if it doesn't exist + //cached, do not assign + Resource *r = ResourceCache::get(path); + res = Ref<Resource>(r); + } else { + //create - res = Ref<Resource>(r); - int_resources[id] = res; - if (!use_nocache) { - res->set_path(path); + Object *obj = ClassDB::instance(type); + if (!obj) { + error_text += "Can't create sub resource of type: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to<Resource>(obj); + if (!r) { + error_text += "Can't create sub resource of type, because not a resource: " + type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + res = Ref<Resource>(r); + do_assign = true; } } @@ -557,7 +557,7 @@ Error ResourceLoaderText::load() { } if (assign != String()) { - if (res.is_valid()) { + if (do_assign) { res->set(assign, value); } //it's assignment @@ -572,6 +572,11 @@ Error ResourceLoaderText::load() { } } + int_resources[id] = res; //always assign int resources + if (do_assign && cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { + res->set_path(path, cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE); + } + if (progress && resources_total > 0) { *progress = resource_current / float(resources_total); } @@ -589,23 +594,33 @@ Error ResourceLoaderText::load() { return error; } - Object *obj = ClassDB::instance(res_type); - if (!obj) { - error_text += "Can't create sub resource of type: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; + if (cache_mode == ResourceFormatLoader::CACHE_MODE_REPLACE && ResourceCache::has(local_path)) { + Resource *r = ResourceCache::get(local_path); + if (r->get_class() == res_type) { + r->reset_state(); + resource = Ref<Resource>(r); + } } - Resource *r = Object::cast_to<Resource>(obj); - if (!r) { - error_text += "Can't create sub resource of type, because not a resource: " + res_type; - _printerr(); - error = ERR_FILE_CORRUPT; - return error; - } + if (!resource.is_valid()) { + Object *obj = ClassDB::instance(res_type); + if (!obj) { + error_text += "Can't create sub resource of type: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } + + Resource *r = Object::cast_to<Resource>(obj); + if (!r) { + error_text += "Can't create sub resource of type, because not a resource: " + res_type; + _printerr(); + error = ERR_FILE_CORRUPT; + return error; + } - resource = Ref<Resource>(r); + resource = Ref<Resource>(r); + } resource_current++; @@ -620,7 +635,7 @@ Error ResourceLoaderText::load() { _printerr(); } else { error = OK; - if (!use_nocache) { + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE) { if (!ResourceCache::has(res_path)) { resource->set_path(res_path); } @@ -668,7 +683,7 @@ Error ResourceLoaderText::load() { error = OK; //get it here resource = packed_scene; - if (!use_nocache && !ResourceCache::has(res_path)) { + if (cache_mode != ResourceFormatLoader::CACHE_MODE_IGNORE && !ResourceCache::has(res_path)) { packed_scene->set_path(res_path); } @@ -699,18 +714,7 @@ void ResourceLoaderText::set_translation_remapped(bool p_remapped) { translation_remapped = p_remapped; } -ResourceLoaderText::ResourceLoaderText() { - use_nocache = false; - - resources_total = 0; - resource_current = 0; - - progress = nullptr; - lines = false; - translation_remapped = false; - use_sub_threads = false; - error = OK; -} +ResourceLoaderText::ResourceLoaderText() {} ResourceLoaderText::~ResourceLoaderText() { memdelete(f); @@ -1252,7 +1256,7 @@ String ResourceLoaderText::recognize(FileAccess *p_f) { ///////////////////// -RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderText::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_CANT_OPEN; } @@ -1265,7 +1269,7 @@ RES ResourceFormatLoaderText::load(const String &p_path, const String &p_origina ResourceLoaderText loader; String path = p_original_path != "" ? p_original_path : p_path; - loader.use_nocache = p_no_cache; + loader.cache_mode = p_cache_mode; loader.use_sub_threads = p_use_sub_threads; loader.local_path = ProjectSettings::get_singleton()->localize_path(path); loader.progress = r_progress; @@ -1317,7 +1321,7 @@ String ResourceFormatLoaderText::get_resource_type(const String &p_path) const { FileAccess *f = FileAccess::open(p_path, FileAccess::READ); if (!f) { - return ""; //could not rwead + return ""; //could not read } ResourceLoaderText loader; diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index ca7b0b021f..2dc683415d 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,12 +38,12 @@ #include "scene/resources/packed_scene.h" class ResourceLoaderText { - bool translation_remapped; + bool translation_remapped = false; String local_path; String res_path; String error_text; - FileAccess *f; + FileAccess *f = nullptr; VariantParser::StreamFile stream; @@ -53,28 +53,28 @@ class ResourceLoaderText { String type; }; - bool is_scene; + bool is_scene = false; String res_type; - bool ignore_resource_parsing; + bool ignore_resource_parsing = false; //Map<String,String> remaps; Map<int, ExtResource> ext_resources; Map<int, RES> int_resources; - int resources_total; - int resource_current; + int resources_total = 0; + int resource_current = 0; String resource_type; VariantParser::Tag next_tag; - bool use_nocache; + ResourceFormatLoader::CacheMode cache_mode = ResourceFormatLoader::CACHE_MODE_REUSE; - bool use_sub_threads; - float *progress; + bool use_sub_threads = false; + float *progress = nullptr; - mutable int lines; + mutable int lines = 0; Map<String, String> remaps; //void _printerr(); @@ -107,7 +107,7 @@ class ResourceLoaderText { friend class ResourceFormatLoaderText; - Error error; + Error error = OK; RES resource; @@ -134,7 +134,7 @@ public: class ResourceFormatLoaderText : public ResourceFormatLoader { public: static ResourceFormatLoaderText *singleton; - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String &p_type) const; @@ -152,11 +152,11 @@ class ResourceFormatSaverTextInstance { Ref<PackedScene> packed_scene; - bool takeover_paths; - bool relative_paths; - bool bundle_resources; - bool skip_editor; - FileAccess *f; + bool takeover_paths = false; + bool relative_paths = false; + bool bundle_resources = false; + bool skip_editor = false; + FileAccess *f = nullptr; struct NonPersistentKey { //for resource properties generated on the fly RES base; @@ -173,7 +173,7 @@ class ResourceFormatSaverTextInstance { struct ResourceSort { RES resource; - int index; + int index = 0; bool operator<(const ResourceSort &p_right) const { return index < p_right.index; } diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp index b1001203a1..35439634f8 100644 --- a/scene/resources/segment_shape_2d.cpp +++ b/scene/resources/segment_shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h index 31a61ea564..f218955061 100644 --- a/scene/resources/segment_shape_2d.h +++ b/scene/resources/segment_shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 76d37eaa71..77c6199794 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -152,9 +152,7 @@ void Shader::_bind_methods() { } Shader::Shader() { - mode = MODE_SPATIAL; shader = RenderingServer::get_singleton()->shader_create(); - params_cache_dirty = true; } Shader::~Shader() { @@ -163,7 +161,7 @@ Shader::~Shader() { //////////// -RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, bool p_no_cache) { +RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { if (r_error) { *r_error = ERR_FILE_CANT_OPEN; } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index 0feaa179b2..6563181ca2 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -51,12 +51,12 @@ public: private: RID shader; - Mode mode; + Mode mode = MODE_SPATIAL; // hack the name of performance // shaders keep a list of ShaderMaterial -> RenderingServer name translations, to make // conversion fast and save memory. - mutable bool params_cache_dirty; + mutable bool params_cache_dirty = true; mutable Map<StringName, StringName> params_cache; //map a shader param to a material param.. Map<StringName, Ref<Texture2D>> default_textures; @@ -102,7 +102,7 @@ VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, bool p_no_cache = false); + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual 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; diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index 94cecc76eb..013b1ef1a9 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -29,7 +29,11 @@ /*************************************************************************/ #include "shape_2d.h" + +#include "core/config/engine.h" +#include "core/config/project_settings.h" #include "servers/physics_server_2d.h" + RID Shape2D::get_rid() const { return shape; } @@ -105,9 +109,17 @@ void Shape2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_solver_bias", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_custom_solver_bias", "get_custom_solver_bias"); } +bool Shape2D::is_collision_outline_enabled() { +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + return true; + } +#endif + return GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true); +} + Shape2D::Shape2D(const RID &p_rid) { shape = p_rid; - custom_bias = 0; } Shape2D::~Shape2D() { diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index 495ffdd38b..14bdd60e4b 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,7 +38,7 @@ class Shape2D : public Resource { OBJ_SAVE_TYPE(Shape2D); RID shape; - real_t custom_bias; + real_t custom_bias = 0.0; protected: static void _bind_methods(); @@ -61,6 +61,9 @@ public: /// Returns the radius of a circle that fully enclose this shape virtual real_t get_enclosing_radius() const = 0; virtual RID get_rid() const override; + + static bool is_collision_outline_enabled(); + Shape2D(); ~Shape2D(); }; diff --git a/scene/resources/shape_3d.cpp b/scene/resources/shape_3d.cpp index 59766f4f1f..5761a405ce 100644 --- a/scene/resources/shape_3d.cpp +++ b/scene/resources/shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -66,7 +66,7 @@ Ref<ArrayMesh> Shape3D::get_debug_mesh() { debug_mesh_cache = Ref<ArrayMesh>(memnew(ArrayMesh)); - if (!lines.empty()) { + if (!lines.is_empty()) { //make mesh Vector<Vector3> array; array.resize(lines.size()); diff --git a/scene/resources/shape_3d.h b/scene/resources/shape_3d.h index 5a9c2e3b9c..0644940fd4 100644 --- a/scene/resources/shape_3d.h +++ b/scene/resources/shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp index e88841a531..fee8fdbde2 100644 --- a/scene/resources/skin.cpp +++ b/scene/resources/skin.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -58,7 +58,7 @@ void Skin::set_bind_name(int p_index, const StringName &p_name) { binds_ptr[p_index].name = p_name; emit_changed(); if (notify_change) { - _change_notify(); + notify_property_list_changed(); } } @@ -81,6 +81,10 @@ void Skin::clear_binds() { emit_changed(); } +void Skin::reset_state() { + clear_binds(); +} + bool Skin::_set(const StringName &p_name, const Variant &p_value) { String name = p_name; if (name == "bind_count") { @@ -153,6 +157,4 @@ void Skin::_bind_methods() { } Skin::Skin() { - bind_count = 0; - binds_ptr = nullptr; } diff --git a/scene/resources/skin.h b/scene/resources/skin.h index e6ed4f1768..f5d64f96aa 100644 --- a/scene/resources/skin.h +++ b/scene/resources/skin.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,14 +44,15 @@ class Skin : public Resource { Vector<Bind> binds; - Bind *binds_ptr; - int bind_count; + Bind *binds_ptr = nullptr; + int bind_count = 0; protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; static void _bind_methods(); public: diff --git a/scene/resources/sky.cpp b/scene/resources/sky.cpp index 7e32516f94..71424ba8ac 100644 --- a/scene/resources/sky.cpp +++ b/scene/resources/sky.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -102,8 +102,6 @@ void Sky::_bind_methods() { } Sky::Sky() { - mode = PROCESS_MODE_AUTOMATIC; - radiance_size = RADIANCE_SIZE_256; sky = RS::get_singleton()->sky_create(); } diff --git a/scene/resources/sky.h b/scene/resources/sky.h index 526ca94317..f0226d321d 100644 --- a/scene/resources/sky.h +++ b/scene/resources/sky.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -59,8 +59,8 @@ public: private: RID sky; - ProcessMode mode; - RadianceSize radiance_size; + ProcessMode mode = PROCESS_MODE_AUTOMATIC; + RadianceSize radiance_size = RADIANCE_SIZE_256; Ref<Material> sky_material; protected: diff --git a/scene/resources/sky_material.cpp b/scene/resources/sky_material.cpp index 05bb13a1e0..b2efecb1cb 100644 --- a/scene/resources/sky_material.cpp +++ b/scene/resources/sky_material.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -522,53 +522,59 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { code += "}\n\n"; code += "void fragment() {\n"; - code += "\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n"; - code += "\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n"; - code += "\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n"; - - code += "\t// rayleigh coefficients\n"; - code += "\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n"; - code += "\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n"; - code += "\t// mie coefficients from Preetham\n"; - code += "\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n"; - - code += "\t// optical length\n"; - code += "\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n"; - code += "\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n"; - code += "\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n"; - code += "\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n"; - - code += "\t// light extinction based on thickness of atmosphere\n"; - code += "\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n"; - - code += "\t// in scattering\n"; - code += "\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n"; - - code += "\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n"; - code += "\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n"; - - code += "\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n"; - code += "\tvec3 betaMTheta = mie_beta * mie_phase;\n\n"; - - code += "\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n"; - code += "\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n"; - code += "\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n"; - - code += "\t// Hack in the ground color\n"; - code += "\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n"; - - code += "\t// Solar disk and out-scattering\n"; - code += "\tfloat sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);\n"; - code += "\tfloat sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);\n"; - code += "\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n"; - code += "\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n"; - code += "\tL0 += texture(night_sky, SKY_COORDS).xyz * extinction;\n\n"; - - code += "\tvec3 color = (Lin + L0) * 0.04;\n"; - code += "\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; - code += "\tCOLOR *= exposure;\n"; - code += "\t// Make optional, eliminates banding\n"; - code += "\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n"; + code += "\tif (LIGHT0_ENABLED) {\n"; + code += "\t\tfloat zenith_angle = clamp( dot(UP, normalize(LIGHT0_DIRECTION)), -1.0, 1.0 );\n"; + code += "\t\tfloat sun_energy = max(0.0, 1.0 - exp(-((PI * 0.5) - acos(zenith_angle)))) * SUN_ENERGY * LIGHT0_ENERGY;\n"; + code += "\t\tfloat sun_fade = 1.0 - clamp(1.0 - exp(LIGHT0_DIRECTION.y), 0.0, 1.0);\n\n"; + + code += "\t\t// rayleigh coefficients\n"; + code += "\t\tfloat rayleigh_coefficient = rayleigh - ( 1.0 * ( 1.0 - sun_fade ) );\n"; + code += "\t\tvec3 rayleigh_beta = rayleigh_coefficient * rayleigh_color.rgb * 0.0001;\n"; + code += "\t\t// mie coefficients from Preetham\n"; + code += "\t\tvec3 mie_beta = turbidity * mie * mie_color.rgb * 0.000434;\n\n"; + + code += "\t\t// optical length\n"; + code += "\t\tfloat zenith = acos(max(0.0, dot(UP, EYEDIR)));\n"; + code += "\t\tfloat optical_mass = 1.0 / (cos(zenith) + 0.15 * pow(93.885 - degrees(zenith), -1.253));\n"; + code += "\t\tfloat rayleigh_scatter = rayleigh_zenith_size * optical_mass;\n"; + code += "\t\tfloat mie_scatter = mie_zenith_size * optical_mass;\n\n"; + + code += "\t\t// light extinction based on thickness of atmosphere\n"; + code += "\t\tvec3 extinction = exp(-(rayleigh_beta * rayleigh_scatter + mie_beta * mie_scatter));\n\n"; + + code += "\t\t// in scattering\n"; + code += "\t\tfloat cos_theta = dot(EYEDIR, normalize(LIGHT0_DIRECTION));\n\n"; + + code += "\t\tfloat rayleigh_phase = (3.0 / (16.0 * PI)) * (1.0 + pow(cos_theta * 0.5 + 0.5, 2.0));\n"; + code += "\t\tvec3 betaRTheta = rayleigh_beta * rayleigh_phase;\n\n"; + + code += "\t\tfloat mie_phase = henyey_greenstein(cos_theta, mie_eccentricity);\n"; + code += "\t\tvec3 betaMTheta = mie_beta * mie_phase;\n\n"; + + code += "\t\tvec3 Lin = pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * (1.0 - extinction), vec3(1.5));\n"; + code += "\t\t// Hack from https://github.com/mrdoob/three.js/blob/master/examples/jsm/objects/Sky.js\n"; + code += "\t\tLin *= mix(vec3(1.0), pow(sun_energy * ((betaRTheta + betaMTheta) / (rayleigh_beta + mie_beta)) * extinction, vec3(0.5)), clamp(pow(1.0 - zenith_angle, 5.0), 0.0, 1.0));\n\n"; + + code += "\t\t// Hack in the ground color\n"; + code += "\t\tLin *= mix(ground_color.rgb, vec3(1.0), smoothstep(-0.1, 0.1, dot(UP, EYEDIR)));\n\n"; + + code += "\t\t// Solar disk and out-scattering\n"; + code += "\t\tfloat sunAngularDiameterCos = cos(LIGHT0_SIZE * sun_disk_scale);\n"; + code += "\t\tfloat sunAngularDiameterCos2 = cos(LIGHT0_SIZE * sun_disk_scale*0.5);\n"; + code += "\t\tfloat sundisk = smoothstep(sunAngularDiameterCos, sunAngularDiameterCos2, cos_theta);\n"; + code += "\t\tvec3 L0 = (sun_energy * 1900.0 * extinction) * sundisk * LIGHT0_COLOR;\n"; + code += "\t\tL0 += texture(night_sky, SKY_COORDS).xyz * extinction;\n\n"; + + code += "\t\tvec3 color = (Lin + L0) * 0.04;\n"; + code += "\t\tCOLOR = pow(color, vec3(1.0 / (1.2 + (1.2 * sun_fade))));\n"; + code += "\t\tCOLOR *= exposure;\n"; + code += "\t\t// Make optional, eliminates banding\n"; + code += "\t\tCOLOR += (hash(EYEDIR * 1741.9782) * 0.08 - 0.04) * 0.016 * dither_strength;\n"; + code += "\t} else {\n"; + code += "\t\t// There is no sun, so display night_sky and nothing else\n"; + code += "\t\tCOLOR = texture(night_sky, SKY_COORDS).xyz * 0.04;\n"; + code += "\t\tCOLOR *= exposure;\n"; + code += "\t}\n"; code += "}\n"; shader = RS::get_singleton()->shader_create(); @@ -591,5 +597,4 @@ PhysicalSkyMaterial::PhysicalSkyMaterial() { PhysicalSkyMaterial::~PhysicalSkyMaterial() { RS::get_singleton()->free(shader); - RS::get_singleton()->material_set_shader(_get_material(), RID()); } diff --git a/scene/resources/sky_material.h b/scene/resources/sky_material.h index 5411994b7d..8fe015519d 100644 --- a/scene/resources/sky_material.h +++ b/scene/resources/sky_material.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -89,7 +89,7 @@ public: float get_sun_curve() const; virtual Shader::Mode get_shader_mode() const override; - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; ProceduralSkyMaterial(); ~ProceduralSkyMaterial(); @@ -114,7 +114,7 @@ public: Ref<Texture2D> get_panorama() const; virtual Shader::Mode get_shader_mode() const override; - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; PanoramaSkyMaterial(); ~PanoramaSkyMaterial(); @@ -180,7 +180,7 @@ public: Ref<Texture2D> get_night_sky() const; virtual Shader::Mode get_shader_mode() const override; - RID get_shader_rid() const; + virtual RID get_shader_rid() const override; PhysicalSkyMaterial(); ~PhysicalSkyMaterial(); diff --git a/scene/resources/sphere_shape_3d.cpp b/scene/resources/sphere_shape_3d.cpp index 64e0a701b7..e4b4398063 100644 --- a/scene/resources/sphere_shape_3d.cpp +++ b/scene/resources/sphere_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -66,7 +66,6 @@ void SphereShape3D::set_radius(float p_radius) { radius = p_radius; _update_shape(); notify_change_to_owners(); - _change_notify("radius"); } float SphereShape3D::get_radius() const { diff --git a/scene/resources/sphere_shape_3d.h b/scene/resources/sphere_shape_3d.h index 5cad67aea5..eddd2a2132 100644 --- a/scene/resources/sphere_shape_3d.h +++ b/scene/resources/sphere_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp new file mode 100644 index 0000000000..90c702081b --- /dev/null +++ b/scene/resources/sprite_frames.cpp @@ -0,0 +1,241 @@ +/*************************************************************************/ +/* sprite_frames.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "sprite_frames.h" + +#include "scene/scene_string_names.h" + +void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + if (p_at_pos >= 0 && p_at_pos < E->get().frames.size()) { + E->get().frames.insert(p_at_pos, p_frame); + } else { + E->get().frames.push_back(p_frame); + } + + emit_changed(); +} + +int SpriteFrames::get_frame_count(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); + + return E->get().frames.size(); +} + +void SpriteFrames::remove_frame(const StringName &p_anim, int p_idx) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + E->get().frames.remove(p_idx); + emit_changed(); +} + +void SpriteFrames::clear(const StringName &p_anim) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + + E->get().frames.clear(); + emit_changed(); +} + +void SpriteFrames::clear_all() { + animations.clear(); + add_animation("default"); +} + +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(); +} + +bool SpriteFrames::has_animation(const StringName &p_anim) const { + return animations.has(p_anim); +} + +void SpriteFrames::remove_animation(const StringName &p_anim) { + animations.erase(p_anim); +} + +void SpriteFrames::rename_animation(const StringName &p_prev, const StringName &p_next) { + ERR_FAIL_COND_MSG(!animations.has(p_prev), "SpriteFrames doesn't have animation '" + String(p_prev) + "'."); + ERR_FAIL_COND_MSG(animations.has(p_next), "Animation '" + String(p_next) + "' already exists."); + + Anim anim = animations[p_prev]; + animations.erase(p_prev); + animations[p_next] = anim; +} + +Vector<String> SpriteFrames::_get_animation_list() const { + Vector<String> ret; + List<StringName> al; + get_animation_list(&al); + for (List<StringName>::Element *E = al.front(); E; E = E->next()) { + ret.push_back(E->get()); + } + + return ret; +} + +void SpriteFrames::get_animation_list(List<StringName> *r_animations) const { + for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + r_animations->push_back(E->key()); + } +} + +Vector<String> SpriteFrames::get_animation_names() const { + Vector<String> names; + for (const Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + names.push_back(E->key()); + } + names.sort(); + return names; +} + +void SpriteFrames::set_animation_speed(const StringName &p_anim, float p_fps) { + ERR_FAIL_COND_MSG(p_fps < 0, "Animation speed cannot be negative (" + itos(p_fps) + ")."); + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + E->get().speed = p_fps; +} + +float SpriteFrames::get_animation_speed(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, 0, "Animation '" + String(p_anim) + "' doesn't exist."); + return E->get().speed; +} + +void SpriteFrames::set_animation_loop(const StringName &p_anim, bool p_loop) { + Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_MSG(!E, "Animation '" + String(p_anim) + "' doesn't exist."); + E->get().loop = p_loop; +} + +bool SpriteFrames::get_animation_loop(const StringName &p_anim) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, false, "Animation '" + String(p_anim) + "' doesn't exist."); + return E->get().loop; +} + +void SpriteFrames::_set_frames(const Array &p_frames) { + clear_all(); + Map<StringName, Anim>::Element *E = animations.find(SceneStringNames::get_singleton()->_default); + ERR_FAIL_COND(!E); + + E->get().frames.resize(p_frames.size()); + for (int i = 0; i < E->get().frames.size(); i++) { + E->get().frames.write[i] = p_frames[i]; + } +} + +Array SpriteFrames::_get_frames() const { + return Array(); +} + +Array SpriteFrames::_get_animations() const { + Array anims; + for (Map<StringName, Anim>::Element *E = animations.front(); E; E = E->next()) { + Dictionary d; + d["name"] = E->key(); + d["speed"] = E->get().speed; + d["loop"] = E->get().loop; + Array frames; + for (int i = 0; i < E->get().frames.size(); i++) { + frames.push_back(E->get().frames[i]); + } + d["frames"] = frames; + anims.push_back(d); + } + + return anims; +} + +void SpriteFrames::_set_animations(const Array &p_animations) { + animations.clear(); + for (int i = 0; i < p_animations.size(); i++) { + Dictionary d = p_animations[i]; + + ERR_CONTINUE(!d.has("name")); + ERR_CONTINUE(!d.has("speed")); + ERR_CONTINUE(!d.has("loop")); + ERR_CONTINUE(!d.has("frames")); + + Anim anim; + anim.speed = d["speed"]; + anim.loop = d["loop"]; + Array frames = d["frames"]; + for (int j = 0; j < frames.size(); j++) { + RES res = frames[j]; + anim.frames.push_back(res); + } + + animations[d["name"]] = anim; + } +} + +void SpriteFrames::_bind_methods() { + ClassDB::bind_method(D_METHOD("add_animation", "anim"), &SpriteFrames::add_animation); + ClassDB::bind_method(D_METHOD("has_animation", "anim"), &SpriteFrames::has_animation); + ClassDB::bind_method(D_METHOD("remove_animation", "anim"), &SpriteFrames::remove_animation); + ClassDB::bind_method(D_METHOD("rename_animation", "anim", "newname"), &SpriteFrames::rename_animation); + + ClassDB::bind_method(D_METHOD("get_animation_names"), &SpriteFrames::get_animation_names); + + ClassDB::bind_method(D_METHOD("set_animation_speed", "anim", "speed"), &SpriteFrames::set_animation_speed); + ClassDB::bind_method(D_METHOD("get_animation_speed", "anim"), &SpriteFrames::get_animation_speed); + + ClassDB::bind_method(D_METHOD("set_animation_loop", "anim", "loop"), &SpriteFrames::set_animation_loop); + ClassDB::bind_method(D_METHOD("get_animation_loop", "anim"), &SpriteFrames::get_animation_loop); + + ClassDB::bind_method(D_METHOD("add_frame", "anim", "frame", "at_position"), &SpriteFrames::add_frame, DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("get_frame_count", "anim"), &SpriteFrames::get_frame_count); + ClassDB::bind_method(D_METHOD("get_frame", "anim", "idx"), &SpriteFrames::get_frame); + ClassDB::bind_method(D_METHOD("set_frame", "anim", "idx", "txt"), &SpriteFrames::set_frame); + ClassDB::bind_method(D_METHOD("remove_frame", "anim", "idx"), &SpriteFrames::remove_frame); + ClassDB::bind_method(D_METHOD("clear", "anim"), &SpriteFrames::clear); + ClassDB::bind_method(D_METHOD("clear_all"), &SpriteFrames::clear_all); + + ClassDB::bind_method(D_METHOD("_set_frames"), &SpriteFrames::_set_frames); + ClassDB::bind_method(D_METHOD("_get_frames"), &SpriteFrames::_get_frames); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "frames", PROPERTY_HINT_NONE, "", 0), "_set_frames", "_get_frames"); //compatibility + + ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations); + ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations); + + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility +} + +SpriteFrames::SpriteFrames() { + add_animation(SceneStringNames::get_singleton()->_default); +} diff --git a/scene/resources/sprite_frames.h b/scene/resources/sprite_frames.h new file mode 100644 index 0000000000..282c5f20ab --- /dev/null +++ b/scene/resources/sprite_frames.h @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* sprite_frames.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 SPRITE_FRAMES_H +#define SPRITE_FRAMES_H + +#include "scene/resources/texture.h" + +class SpriteFrames : public Resource { + GDCLASS(SpriteFrames, Resource); + + struct Anim { + float speed = 5.0; + bool loop = true; + Vector<Ref<Texture2D>> frames; + }; + + Map<StringName, Anim> animations; + + Array _get_frames() const; + void _set_frames(const Array &p_frames); + + Array _get_animations() const; + void _set_animations(const Array &p_animations); + + Vector<String> _get_animation_list() const; + +protected: + static void _bind_methods(); + +public: + void add_animation(const StringName &p_anim); + bool has_animation(const StringName &p_anim) const; + void remove_animation(const StringName &p_anim); + void rename_animation(const StringName &p_prev, const StringName &p_next); + + void get_animation_list(List<StringName> *r_animations) const; + Vector<String> get_animation_names() const; + + void set_animation_speed(const StringName &p_anim, float p_fps); + float get_animation_speed(const StringName &p_anim) const; + + void set_animation_loop(const StringName &p_anim, bool p_loop); + bool get_animation_loop(const StringName &p_anim) const; + + void add_frame(const StringName &p_anim, const Ref<Texture2D> &p_frame, int p_at_pos = -1); + int get_frame_count(const StringName &p_anim) const; + _FORCE_INLINE_ Ref<Texture2D> get_frame(const StringName &p_anim, int p_idx) const { + const Map<StringName, Anim>::Element *E = animations.find(p_anim); + ERR_FAIL_COND_V_MSG(!E, Ref<Texture2D>(), "Animation '" + String(p_anim) + "' doesn't exist."); + ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); + if (p_idx >= E->get().frames.size()) { + return Ref<Texture2D>(); + } + + return E->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."); + ERR_FAIL_COND(p_idx < 0); + if (p_idx >= E->get().frames.size()) { + return; + } + E->get().frames.write[p_idx] = p_frame; + } + void remove_frame(const StringName &p_anim, int p_idx); + void clear(const StringName &p_anim); + void clear_all(); + + SpriteFrames(); +}; + +#endif // SPRITE_FRAMES_H diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 14197c6c68..2159f1bc97 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -38,26 +38,26 @@ bool StyleBox::test_mask(const Point2 &p_point, const Rect2 &p_rect) const { return true; } -void StyleBox::set_default_margin(Margin p_margin, float p_value) { - ERR_FAIL_INDEX((int)p_margin, 4); +void StyleBox::set_default_margin(Side p_side, float p_value) { + ERR_FAIL_INDEX((int)p_side, 4); - margin[p_margin] = p_value; + margin[p_side] = p_value; emit_changed(); } -float StyleBox::get_default_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBox::get_default_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } -float StyleBox::get_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBox::get_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - if (margin[p_margin] < 0) { - return get_style_margin(p_margin); + if (margin[p_side] < 0) { + return get_style_margin(p_side); } else { - return margin[p_margin]; + return margin[p_side]; } } @@ -66,11 +66,11 @@ CanvasItem *StyleBox::get_current_item_drawn() const { } Size2 StyleBox::get_minimum_size() const { - return Size2(get_margin(MARGIN_LEFT) + get_margin(MARGIN_RIGHT), get_margin(MARGIN_TOP) + get_margin(MARGIN_BOTTOM)); + return Size2(get_margin(SIDE_LEFT) + get_margin(SIDE_RIGHT), get_margin(SIDE_TOP) + get_margin(SIDE_BOTTOM)); } Point2 StyleBox::get_offset() const { - return Point2(get_margin(MARGIN_LEFT), get_margin(MARGIN_TOP)); + return Point2(get_margin(SIDE_LEFT), get_margin(SIDE_TOP)); } Size2 StyleBox::get_center_size() const { @@ -99,10 +99,10 @@ void StyleBox::_bind_methods() { ClassDB::bind_method(D_METHOD("draw", "canvas_item", "rect"), &StyleBox::draw); ADD_GROUP("Content Margin", "content_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_left", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_right", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_top", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "content_margin_bottom", PROPERTY_HINT_RANGE, "-1,2048,1"), "set_default_margin", "get_default_margin", SIDE_BOTTOM); } StyleBox::StyleBox() { @@ -123,41 +123,33 @@ void StyleBoxTexture::set_texture(Ref<Texture2D> p_texture) { } emit_signal("texture_changed"); emit_changed(); - _change_notify("texture"); } Ref<Texture2D> StyleBoxTexture::get_texture() const { return texture; } -void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) { - ERR_FAIL_INDEX((int)p_margin, 4); +void StyleBoxTexture::set_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); - margin[p_margin] = p_size; + margin[p_side] = p_size; emit_changed(); - static const char *margin_prop[4] = { - "content_margin_left", - "content_margin_top", - "content_margin_right", - "content_margin_bottom", - }; - _change_notify(margin_prop[p_margin]); } -float StyleBoxTexture::get_margin_size(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBoxTexture::get_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } -float StyleBoxTexture::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); +float StyleBoxTexture::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); - return margin[p_margin]; + return margin[p_side]; } Rect2 StyleBoxTexture::get_draw_rect(const Rect2 &p_rect) const { - return p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + return p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); } void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { @@ -170,12 +162,12 @@ void StyleBoxTexture::draw(RID p_canvas_item, const Rect2 &p_rect) const { texture->get_rect_region(rect, src_rect, rect, src_rect); - rect.position.x -= expand_margin[MARGIN_LEFT]; - rect.position.y -= expand_margin[MARGIN_TOP]; - rect.size.x += expand_margin[MARGIN_LEFT] + expand_margin[MARGIN_RIGHT]; - rect.size.y += expand_margin[MARGIN_TOP] + expand_margin[MARGIN_BOTTOM]; + rect.position.x -= expand_margin[SIDE_LEFT]; + rect.position.y -= expand_margin[SIDE_TOP]; + rect.size.x += expand_margin[SIDE_LEFT] + expand_margin[SIDE_RIGHT]; + rect.size.y += expand_margin[SIDE_TOP] + expand_margin[SIDE_BOTTOM]; - 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); + RenderingServer::get_singleton()->canvas_item_add_nine_patch(p_canvas_item, rect, src_rect, texture->get_rid(), Vector2(margin[SIDE_LEFT], margin[SIDE_TOP]), Vector2(margin[SIDE_RIGHT], margin[SIDE_BOTTOM]), RS::NinePatchAxisMode(axis_h), RS::NinePatchAxisMode(axis_v), draw_center, modulate); } void StyleBoxTexture::set_draw_center(bool p_enabled) { @@ -195,17 +187,17 @@ Size2 StyleBoxTexture::get_center_size() const { return region_rect.size - get_minimum_size(); } -void StyleBoxTexture::set_expand_margin_size(Margin p_expand_margin, float p_size) { - ERR_FAIL_INDEX((int)p_expand_margin, 4); - expand_margin[p_expand_margin] = p_size; +void StyleBoxTexture::set_expand_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + expand_margin[p_side] = p_size; emit_changed(); } void StyleBoxTexture::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { - expand_margin[MARGIN_LEFT] = p_left; - expand_margin[MARGIN_TOP] = p_top; - expand_margin[MARGIN_RIGHT] = p_right; - expand_margin[MARGIN_BOTTOM] = p_bottom; + expand_margin[SIDE_LEFT] = p_left; + expand_margin[SIDE_TOP] = p_top; + expand_margin[SIDE_RIGHT] = p_right; + expand_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } @@ -216,9 +208,9 @@ void StyleBoxTexture::set_expand_margin_size_all(float p_expand_margin_size) { emit_changed(); } -float StyleBoxTexture::get_expand_margin_size(Margin p_expand_margin) const { - ERR_FAIL_INDEX_V((int)p_expand_margin, 4, 0); - return expand_margin[p_expand_margin]; +float StyleBoxTexture::get_expand_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return expand_margin[p_side]; } void StyleBoxTexture::set_region_rect(const Rect2 &p_region_rect) { @@ -228,7 +220,6 @@ 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 { @@ -299,15 +290,15 @@ void StyleBoxTexture::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture"); ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect"); ADD_GROUP("Margin", "margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_margin_size", "get_margin_size", SIDE_BOTTOM); ADD_GROUP("Expand Margin", "expand_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin_size", "get_expand_margin_size", SIDE_BOTTOM); ADD_GROUP("Axis Stretch", "axis_stretch_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_horizontal", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_h_axis_stretch_mode", "get_h_axis_stretch_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "axis_stretch_vertical", PROPERTY_HINT_ENUM, "Stretch,Tile,Tile Fit"), "set_v_axis_stretch_mode", "get_v_axis_stretch_mode"); @@ -320,20 +311,9 @@ void StyleBoxTexture::_bind_methods() { BIND_ENUM_CONSTANT(AXIS_STRETCH_MODE_TILE_FIT); } -StyleBoxTexture::StyleBoxTexture() { - for (int i = 0; i < 4; i++) { - margin[i] = 0; - expand_margin[i] = 0; - } - draw_center = true; - modulate = Color(1, 1, 1, 1); - - axis_h = AXIS_STRETCH_MODE_STRETCH; - axis_v = AXIS_STRETCH_MODE_STRETCH; -} +StyleBoxTexture::StyleBoxTexture() {} -StyleBoxTexture::~StyleBoxTexture() { -} +StyleBoxTexture::~StyleBoxTexture() {} //////////////// @@ -367,15 +347,15 @@ int StyleBoxFlat::get_border_width_min() const { return MIN(MIN(border_width[0], border_width[1]), MIN(border_width[2], border_width[3])); } -void StyleBoxFlat::set_border_width(Margin p_margin, int p_width) { - ERR_FAIL_INDEX((int)p_margin, 4); - border_width[p_margin] = p_width; +void StyleBoxFlat::set_border_width(Side p_side, int p_width) { + ERR_FAIL_INDEX((int)p_side, 4); + border_width[p_side] = p_width; emit_changed(); } -int StyleBoxFlat::get_border_width(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0); - return border_width[p_margin]; +int StyleBoxFlat::get_border_width(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + return border_width[p_side]; } void StyleBoxFlat::set_border_blend(bool p_blend) { @@ -395,10 +375,10 @@ void StyleBoxFlat::set_corner_radius_all(int radius) { emit_changed(); } -void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left) { +void StyleBoxFlat::set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left) { corner_radius[0] = radius_top_left; corner_radius[1] = radius_top_right; - corner_radius[2] = radius_botton_right; + corner_radius[2] = radius_bottom_right; corner_radius[3] = radius_bottom_left; emit_changed(); @@ -415,17 +395,17 @@ int StyleBoxFlat::get_corner_radius(const Corner p_corner) const { return corner_radius[p_corner]; } -void StyleBoxFlat::set_expand_margin_size(Margin p_expand_margin, float p_size) { - ERR_FAIL_INDEX((int)p_expand_margin, 4); - expand_margin[p_expand_margin] = p_size; +void StyleBoxFlat::set_expand_margin_size(Side p_side, float p_size) { + ERR_FAIL_INDEX((int)p_side, 4); + expand_margin[p_side] = p_size; emit_changed(); } void StyleBoxFlat::set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom) { - expand_margin[MARGIN_LEFT] = p_left; - expand_margin[MARGIN_TOP] = p_top; - expand_margin[MARGIN_RIGHT] = p_right; - expand_margin[MARGIN_BOTTOM] = p_bottom; + expand_margin[SIDE_LEFT] = p_left; + expand_margin[SIDE_TOP] = p_top; + expand_margin[SIDE_RIGHT] = p_right; + expand_margin[SIDE_BOTTOM] = p_bottom; emit_changed(); } @@ -436,9 +416,9 @@ void StyleBoxFlat::set_expand_margin_size_all(float p_expand_margin_size) { emit_changed(); } -float StyleBoxFlat::get_expand_margin_size(Margin p_expand_margin) const { - ERR_FAIL_INDEX_V((int)p_expand_margin, 4, 0.0); - return expand_margin[p_expand_margin]; +float StyleBoxFlat::get_expand_margin_size(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); + return expand_margin[p_side]; } void StyleBoxFlat::set_draw_center(bool p_enabled) { @@ -480,6 +460,7 @@ Point2 StyleBoxFlat::get_shadow_offset() const { void StyleBoxFlat::set_anti_aliased(const bool &p_anti_aliased) { anti_aliased = p_anti_aliased; emit_changed(); + notify_property_list_changed(); } bool StyleBoxFlat::is_anti_aliased() const { @@ -576,8 +557,8 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color color = outer_color; corner_point = outer_points[corner_index]; } - float x = radius * (float)cos((double)corner_index * Math_PI / 2.0 + (double)detail / (double)adapted_corner_detail * Math_PI / 2.0 + Math_PI) + corner_point.x; - float y = radius * (float)sin((double)corner_index * Math_PI / 2.0 + (double)detail / (double)adapted_corner_detail * Math_PI / 2.0 + Math_PI) + corner_point.y; + real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x; + real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y; verts.push_back(Vector2(x, y)); colors.push_back(color); } @@ -633,7 +614,7 @@ inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, cons } Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const { - Rect2 draw_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + Rect2 draw_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); if (shadow_size > 0) { Rect2 shadow_rect = draw_rect.grow(shadow_size); @@ -652,7 +633,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { return; } - Rect2 style_rect = p_rect.grow_individual(expand_margin[MARGIN_LEFT], expand_margin[MARGIN_TOP], expand_margin[MARGIN_RIGHT], expand_margin[MARGIN_BOTTOM]); + Rect2 style_rect = p_rect.grow_individual(expand_margin[SIDE_LEFT], expand_margin[SIDE_TOP], expand_margin[SIDE_RIGHT], expand_margin[SIDE_BOTTOM]); if (Math::is_zero_approx(style_rect.size.width) || Math::is_zero_approx(style_rect.size.height)) { return; } @@ -671,23 +652,23 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { int width = MAX(style_rect.size.width, 0); int height = MAX(style_rect.size.height, 0); int adapted_border[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - adapt_values(MARGIN_TOP, MARGIN_BOTTOM, adapted_border, border_width, height, height, height); - adapt_values(MARGIN_LEFT, MARGIN_RIGHT, adapted_border, border_width, width, width, width); + adapt_values(SIDE_TOP, SIDE_BOTTOM, adapted_border, border_width, height, height, height); + adapt_values(SIDE_LEFT, SIDE_RIGHT, adapted_border, border_width, width, width, width); //adapt corners (prevent weird overlapping/glitchy drawings) int adapted_corner[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX }; - adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]); - adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]); - adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[MARGIN_RIGHT], width - adapted_border[MARGIN_LEFT]); - adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[MARGIN_RIGHT], width - adapted_border[MARGIN_LEFT]); + adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]); + adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[SIDE_BOTTOM], height - adapted_border[SIDE_TOP]); + adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]); + adapt_values(CORNER_BOTTOM_LEFT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[SIDE_RIGHT], width - adapted_border[SIDE_LEFT]); - Rect2 infill_rect = style_rect.grow_individual(-adapted_border[MARGIN_LEFT], -adapted_border[MARGIN_TOP], -adapted_border[MARGIN_RIGHT], -adapted_border[MARGIN_BOTTOM]); + Rect2 infill_rect = style_rect.grow_individual(-adapted_border[SIDE_LEFT], -adapted_border[SIDE_TOP], -adapted_border[SIDE_RIGHT], -adapted_border[SIDE_BOTTOM]); Rect2 border_style_rect = style_rect; if (aa_on) { for (int i = 0; i < 4; i++) { if (border_width[i] > 0) { - border_style_rect = border_style_rect.grow_margin((Margin)i, -aa_size_grow); + border_style_rect = border_style_rect.grow_side((Side)i, -aa_size_grow); } } } @@ -748,8 +729,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { } } - Rect2 infill_inner_rect = infill_rect.grow_individual(-aa_border_width[MARGIN_LEFT], -aa_border_width[MARGIN_TOP], - -aa_border_width[MARGIN_RIGHT], -aa_border_width[MARGIN_BOTTOM]); + Rect2 infill_inner_rect = infill_rect.grow_individual(-aa_border_width[SIDE_LEFT], -aa_border_width[SIDE_TOP], + -aa_border_width[SIDE_RIGHT], -aa_border_width[SIDE_BOTTOM]); if (draw_center) { if (!blend_on && draw_border) { @@ -759,8 +740,8 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { } if (!blend_on || !draw_border) { - Rect2 infill_aa_rect = infill_rect.grow_individual(aa_fill_width[MARGIN_LEFT], aa_fill_width[MARGIN_TOP], - aa_fill_width[MARGIN_RIGHT], aa_fill_width[MARGIN_BOTTOM]); + Rect2 infill_aa_rect = infill_rect.grow_individual(aa_fill_width[SIDE_LEFT], aa_fill_width[SIDE_TOP], + aa_fill_width[SIDE_RIGHT], aa_fill_width[SIDE_BOTTOM]); Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0); @@ -796,9 +777,15 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const { vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs); } -float StyleBoxFlat::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, 0.0); - return border_width[p_margin]; +float StyleBoxFlat::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0.0); + return border_width[p_side]; +} + +void StyleBoxFlat::_validate_property(PropertyInfo &property) const { + if (!anti_aliased && property.name == "anti_aliasing_size") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } } void StyleBoxFlat::_bind_methods() { @@ -854,10 +841,10 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_center"), "set_draw_center", "is_draw_center_enabled"); ADD_GROUP("Border Width", "border_width_"); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_left", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_top", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_right", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::INT, "border_width_bottom", PROPERTY_HINT_RANGE, "0,1024,1"), "set_border_width", "get_border_width", SIDE_BOTTOM); ADD_GROUP("Border", "border_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "border_color"), "set_border_color", "get_border_color"); @@ -873,10 +860,10 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "corner_detail", PROPERTY_HINT_RANGE, "1,20,1"), "set_corner_detail", "get_corner_detail"); ADD_GROUP("Expand Margin", "expand_margin_"); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_LEFT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_RIGHT); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_TOP); - ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", MARGIN_BOTTOM); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_left", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_LEFT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_right", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_RIGHT); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_top", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_TOP); + ADD_PROPERTYI(PropertyInfo(Variant::FLOAT, "expand_margin_bottom", PROPERTY_HINT_RANGE, "0,2048,1"), "set_expand_margin", "get_expand_margin", SIDE_BOTTOM); ADD_GROUP("Shadow", "shadow_"); ADD_PROPERTY(PropertyInfo(Variant::COLOR, "shadow_color"), "set_shadow_color", "get_shadow_color"); @@ -888,38 +875,9 @@ void StyleBoxFlat::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "1,5,1"), "set_aa_size", "get_aa_size"); } -StyleBoxFlat::StyleBoxFlat() { - bg_color = Color(0.6, 0.6, 0.6); - shadow_color = Color(0, 0, 0, 0.6); - border_color = Color(0.8, 0.8, 0.8); - - blend_border = false; - draw_center = true; - anti_aliased = true; - - shadow_size = 0; - shadow_offset = Point2(0, 0); - corner_detail = 8; - aa_size = 1; - - border_width[0] = 0; - border_width[1] = 0; - border_width[2] = 0; - border_width[3] = 0; +StyleBoxFlat::StyleBoxFlat() {} - expand_margin[0] = 0; - expand_margin[1] = 0; - expand_margin[2] = 0; - expand_margin[3] = 0; - - corner_radius[0] = 0; - corner_radius[1] = 0; - corner_radius[2] = 0; - corner_radius[3] = 0; -} - -StyleBoxFlat::~StyleBoxFlat() { -} +StyleBoxFlat::~StyleBoxFlat() {} void StyleBoxLine::set_color(const Color &p_color) { color = p_color; @@ -985,9 +943,18 @@ void StyleBoxLine::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical"); } -float StyleBoxLine::get_style_margin(Margin p_margin) const { - ERR_FAIL_INDEX_V((int)p_margin, 4, thickness); - return thickness; +float StyleBoxLine::get_style_margin(Side p_side) const { + ERR_FAIL_INDEX_V((int)p_side, 4, 0); + + if (vertical) { + if (p_side == SIDE_LEFT || p_side == SIDE_RIGHT) { + return thickness / 2.0; + } + } else if (p_side == SIDE_TOP || p_side == SIDE_BOTTOM) { + return thickness / 2.0; + } + + return 0; } Size2 StyleBoxLine::get_center_size() const { @@ -1011,12 +978,6 @@ void StyleBoxLine::draw(RID p_canvas_item, const Rect2 &p_rect) const { vs->canvas_item_add_rect(p_canvas_item, r, color); } -StyleBoxLine::StyleBoxLine() { - grow_begin = 1.0; - grow_end = 1.0; - thickness = 1; - color = Color(0.0, 0.0, 0.0); - vertical = false; -} +StyleBoxLine::StyleBoxLine() {} StyleBoxLine::~StyleBoxLine() {} diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h index 7dd806e840..dd5c873a00 100644 --- a/scene/resources/style_box.h +++ b/scene/resources/style_box.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,15 +44,15 @@ class StyleBox : public Resource { float margin[4]; protected: - virtual float get_style_margin(Margin p_margin) const = 0; + virtual float get_style_margin(Side p_side) const = 0; static void _bind_methods(); public: virtual bool test_mask(const Point2 &p_point, const Rect2 &p_rect) const; - void set_default_margin(Margin p_margin, float p_value); - float get_default_margin(Margin p_margin) const; - float get_margin(Margin p_margin) const; + void set_default_margin(Side p_side, float p_value); + float get_default_margin(Side p_side) const; + float get_margin(Side p_side) const; virtual Size2 get_center_size() const; virtual Rect2 get_draw_rect(const Rect2 &p_rect) const; @@ -68,7 +68,7 @@ public: class StyleBoxEmpty : public StyleBox { GDCLASS(StyleBoxEmpty, StyleBox); - virtual float get_style_margin(Margin p_margin) const override { return 0; } + virtual float get_style_margin(Side p_side) const override { return 0; } public: virtual void draw(RID p_canvas_item, const Rect2 &p_rect) const override {} @@ -86,27 +86,27 @@ public: }; private: - float expand_margin[4]; - float margin[4]; + float expand_margin[4] = {}; + float margin[4] = {}; Rect2 region_rect; Ref<Texture2D> texture; - bool draw_center; - Color modulate; - AxisStretchMode axis_h; - AxisStretchMode axis_v; + bool draw_center = true; + Color modulate = Color(1, 1, 1, 1); + AxisStretchMode axis_h = AXIS_STRETCH_MODE_STRETCH; + AxisStretchMode axis_v = AXIS_STRETCH_MODE_STRETCH; protected: - virtual float get_style_margin(Margin p_margin) const override; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); public: - void set_expand_margin_size(Margin p_expand_margin, float p_size); + void set_expand_margin_size(Side p_expand_side, float p_size); void set_expand_margin_size_all(float p_expand_margin_size); void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Margin p_expand_margin) const; + float get_expand_margin_size(Side p_expand_side) const; - void set_margin_size(Margin p_margin, float p_size); - float get_margin_size(Margin p_margin) const; + void set_margin_size(Side p_side, float p_size); + float get_margin_size(Side p_side) const; void set_region_rect(const Rect2 &p_region_rect); Rect2 get_region_rect() const; @@ -139,26 +139,27 @@ VARIANT_ENUM_CAST(StyleBoxTexture::AxisStretchMode) class StyleBoxFlat : public StyleBox { GDCLASS(StyleBoxFlat, StyleBox); - Color bg_color; - Color shadow_color; - Color border_color; + Color bg_color = Color(0.6, 0.6, 0.6); + Color shadow_color = Color(0, 0, 0, 0.6); + Color border_color = Color(0.8, 0.8, 0.8); - int border_width[4]; - int expand_margin[4]; - int corner_radius[4]; + int border_width[4] = {}; + int expand_margin[4] = {}; + int corner_radius[4] = {}; - bool draw_center; - bool blend_border; - bool anti_aliased; + bool draw_center = true; + bool blend_border = false; + bool anti_aliased = true; - int corner_detail; - int shadow_size; + int corner_detail = 8; + int shadow_size = 0; Point2 shadow_offset; - int aa_size; + int aa_size = 1; protected: - virtual float get_style_margin(Margin p_margin) const override; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); + void _validate_property(PropertyInfo &property) const override; public: //Color @@ -174,8 +175,8 @@ public: void set_border_width_all(int p_size); int get_border_width_min() const; - void set_border_width(Margin p_margin, int p_width); - int get_border_width(Margin p_margin) const; + void set_border_width(Side p_side, int p_width); + int get_border_width(Side p_side) const; //blend void set_border_blend(bool p_blend); @@ -183,7 +184,7 @@ public: //CORNER void set_corner_radius_all(int radius); - void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_botton_right, const int radius_bottom_left); + void set_corner_radius_individual(const int radius_top_left, const int radius_top_right, const int radius_bottom_right, const int radius_bottom_left); void set_corner_radius(Corner p_corner, const int radius); int get_corner_radius(Corner p_corner) const; @@ -192,10 +193,10 @@ public: int get_corner_detail() const; //EXPANDS - void set_expand_margin_size(Margin p_expand_margin, float p_size); + void set_expand_margin_size(Side p_expand_side, float p_size); void set_expand_margin_size_all(float p_expand_margin_size); void set_expand_margin_size_individual(float p_left, float p_top, float p_right, float p_bottom); - float get_expand_margin_size(Margin p_expand_margin) const; + float get_expand_margin_size(Side p_expand_side) const; //DRAW CENTER void set_draw_center(bool p_enabled); @@ -231,13 +232,13 @@ public: class StyleBoxLine : public StyleBox { GDCLASS(StyleBoxLine, StyleBox); Color color; - int thickness; - bool vertical; - float grow_begin; - float grow_end; + int thickness = 1; + bool vertical = false; + float grow_begin = 1.0; + float grow_end = 1.0; protected: - virtual float get_style_margin(Margin p_margin) const override; + virtual float get_style_margin(Side p_side) const override; static void _bind_methods(); public: diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 50308d641a..3d3900ecc5 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,6 +35,8 @@ SurfaceTool::OptimizeVertexCacheFunc SurfaceTool::optimize_vertex_cache_func = nullptr; SurfaceTool::SimplifyFunc SurfaceTool::simplify_func = nullptr; +SurfaceTool::SimplifyScaleFunc SurfaceTool::simplify_scale_func = nullptr; +SurfaceTool::SimplifySloppyFunc SurfaceTool::simplify_sloppy_func = nullptr; bool SurfaceTool::Vertex::operator==(const Vertex &p_vertex) const { if (vertex != p_vertex.vertex) { @@ -158,7 +160,7 @@ void SurfaceTool::add_vertex(const Vector3 &p_vertex) { //cap weights.resize(expected_vertices); //renormalize - float total = 0; + float total = 0.0; for (int i = 0; i < expected_vertices; i++) { total += weights[i].weight; } @@ -297,6 +299,7 @@ void SurfaceTool::add_triangle_fan(const Vector<Vector3> &p_vertices, const Vect void SurfaceTool::add_index(int p_index) { ERR_FAIL_COND(!begun); + ERR_FAIL_COND(p_index < 0); format |= Mesh::ARRAY_FORMAT_INDEX; index_array.push_back(p_index); @@ -1056,6 +1059,10 @@ void SurfaceTool::set_material(const Ref<Material> &p_material) { material = p_material; } +Ref<Material> SurfaceTool::get_material() const { + return material; +} + void SurfaceTool::clear() { begun = false; primitive = Mesh::PRIMITIVE_LINES; @@ -1085,6 +1092,10 @@ void SurfaceTool::set_custom_format(int p_index, CustomFormat p_format) { ERR_FAIL_COND(begun); last_custom_format[p_index] = p_format; } + +Mesh::PrimitiveType SurfaceTool::get_primitive() const { + return primitive; +} SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_index) const { ERR_FAIL_INDEX_V(p_index, RS::ARRAY_CUSTOM_COUNT, CUSTOM_MAX); return last_custom_format[p_index]; @@ -1171,6 +1182,7 @@ void SurfaceTool::_bind_methods() { ClassDB::bind_method(D_METHOD("generate_lod", "nd_threshold", "target_index_count"), &SurfaceTool::generate_lod, DEFVAL(3)); ClassDB::bind_method(D_METHOD("set_material", "material"), &SurfaceTool::set_material); + ClassDB::bind_method(D_METHOD("get_primitive"), &SurfaceTool::get_primitive); ClassDB::bind_method(D_METHOD("clear"), &SurfaceTool::clear); @@ -1194,12 +1206,7 @@ void SurfaceTool::_bind_methods() { } SurfaceTool::SurfaceTool() { - first = false; - begun = false; for (int i = 0; i < RS::ARRAY_CUSTOM_COUNT; i++) { last_custom_format[i] = CUSTOM_MAX; } - primitive = Mesh::PRIMITIVE_LINES; - skin_weights = SKIN_4_WEIGHTS; - format = 0; } diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index 0e60bfe389..28addf2245 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -78,6 +78,10 @@ public: static OptimizeVertexCacheFunc optimize_vertex_cache_func; typedef size_t (*SimplifyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *r_error); static SimplifyFunc simplify_func; + typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride); + static SimplifyScaleFunc simplify_scale_func; + typedef size_t (*SimplifySloppyFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error, float *out_result_error); + static SimplifySloppyFunc simplify_sloppy_func; private: struct VertexHasher { @@ -85,17 +89,17 @@ private: }; struct WeightSort { - int index; - float weight; + int index = 0; + float weight = 0.0; bool operator<(const WeightSort &p_right) const { return weight < p_right.weight; } }; - bool begun; - bool first; - Mesh::PrimitiveType primitive; - uint32_t format; + bool begun = false; + bool first = false; + Mesh::PrimitiveType primitive = Mesh::PRIMITIVE_LINES; + uint32_t format = 0; Ref<Material> material; //arrays LocalVector<Vertex> vertex_array; @@ -111,7 +115,7 @@ private: Plane last_tangent; uint32_t last_smooth_group = 0; - SkinWeightCount skin_weights; + SkinWeightCount skin_weights = SKIN_4_WEIGHTS; Color last_custom[RS::ARRAY_CUSTOM_COUNT]; @@ -139,6 +143,8 @@ public: void set_custom_format(int p_index, CustomFormat p_format); CustomFormat get_custom_format(int p_index) const; + Mesh::PrimitiveType get_primitive() const; + void begin(Mesh::PrimitiveType p_primitive); void set_color(Color p_color); @@ -167,6 +173,7 @@ public: Vector<int> generate_lod(float p_threshold, int p_target_index_count = 3); void set_material(const Ref<Material> &p_material); + Ref<Material> get_material() const; void clear(); diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp index e3e4373fa9..9dd00849f4 100644 --- a/scene/resources/syntax_highlighter.cpp +++ b/scene/resources/syntax_highlighter.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -110,16 +110,13 @@ TextEdit *SyntaxHighlighter::get_text_edit() { } void SyntaxHighlighter::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_line_syntax_highlighting", "p_line"), &SyntaxHighlighter::get_line_syntax_highlighting); + ClassDB::bind_method(D_METHOD("get_line_syntax_highlighting", "line"), &SyntaxHighlighter::get_line_syntax_highlighting); ClassDB::bind_method(D_METHOD("update_cache"), &SyntaxHighlighter::update_cache); ClassDB::bind_method(D_METHOD("clear_highlighting_cache"), &SyntaxHighlighter::clear_highlighting_cache); ClassDB::bind_method(D_METHOD("get_text_edit"), &SyntaxHighlighter::get_text_edit); - ClassDB::bind_method(D_METHOD("_get_line_syntax_highlighting", "p_line"), &SyntaxHighlighter::_get_line_syntax_highlighting); - ClassDB::bind_method(D_METHOD("_update_cache"), &SyntaxHighlighter::_update_cache); - ClassDB::bind_method(D_METHOD("_clear_highlighting_cache"), &SyntaxHighlighter::_clear_highlighting_cache); - - BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_line_syntax_highlighting", PropertyInfo(Variant::INT, "p_line"))); + BIND_VMETHOD(MethodInfo(Variant::DICTIONARY, "_get_line_syntax_highlighting", PropertyInfo(Variant::INT, "line"))); + BIND_VMETHOD(MethodInfo("_clear_highlighting_cache")); BIND_VMETHOD(MethodInfo("_update_cache")); } @@ -552,7 +549,7 @@ Dictionary CodeHighlighter::get_color_regions() const { Dictionary r_color_regions; for (int i = 0; i < color_regions.size(); i++) { ColorRegion region = color_regions[i]; - r_color_regions[region.start_key + (region.end_key.empty() ? "" : " " + region.end_key)] = region.color; + r_color_regions[region.start_key + (region.end_key.is_empty() ? "" : " " + region.end_key)] = region.color; } return r_color_regions; } @@ -576,11 +573,11 @@ void CodeHighlighter::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_member_keyword_colors"), &CodeHighlighter::clear_member_keyword_colors); ClassDB::bind_method(D_METHOD("get_member_keyword_colors"), &CodeHighlighter::get_member_keyword_colors); - ClassDB::bind_method(D_METHOD("add_color_region", "p_start_key", "p_end_key", "p_color", "p_line_only"), &CodeHighlighter::add_color_region, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("remove_color_region", "p_start_key"), &CodeHighlighter::remove_color_region); - ClassDB::bind_method(D_METHOD("has_color_region", "p_start_key"), &CodeHighlighter::has_color_region); + ClassDB::bind_method(D_METHOD("add_color_region", "start_key", "end_key", "color", "line_only"), &CodeHighlighter::add_color_region, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("remove_color_region", "start_key"), &CodeHighlighter::remove_color_region); + ClassDB::bind_method(D_METHOD("has_color_region", "start_key"), &CodeHighlighter::has_color_region); - ClassDB::bind_method(D_METHOD("set_color_regions", "p_color_regions"), &CodeHighlighter::set_color_regions); + ClassDB::bind_method(D_METHOD("set_color_regions", "color_regions"), &CodeHighlighter::set_color_regions); ClassDB::bind_method(D_METHOD("clear_color_regions"), &CodeHighlighter::clear_color_regions); ClassDB::bind_method(D_METHOD("get_color_regions"), &CodeHighlighter::get_color_regions); diff --git a/scene/resources/syntax_highlighter.h b/scene/resources/syntax_highlighter.h index 62865920d3..f3964b0c8f 100644 --- a/scene/resources/syntax_highlighter.h +++ b/scene/resources/syntax_highlighter.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -75,7 +75,7 @@ private: Color color; String start_key; String end_key; - bool line_only; + bool line_only = false; }; Vector<ColorRegion> color_regions; Map<int, int> color_region_cache; diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp index e3bd5ce0ae..cf07003720 100644 --- a/scene/resources/text_file.cpp +++ b/scene/resources/text_file.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/text_file.h b/scene/resources/text_file.h index fa812b1e67..005075a218 100644 --- a/scene/resources/text_file.h +++ b/scene/resources/text_file.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/text_line.cpp b/scene/resources/text_line.cpp index cc9b6758b6..925867a1f2 100644 --- a/scene/resources/text_line.cpp +++ b/scene/resources/text_line.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -97,7 +97,7 @@ void TextLine::_bind_methods() { void TextLine::_shape() { if (dirty) { - if (!tab_stops.empty()) { + if (!tab_stops.is_empty()) { TS->shaped_text_tab_align(rid, tab_stops); } if (align == HALIGN_FILL) { @@ -167,6 +167,7 @@ void TextLine::set_bidi_override(const Vector<Vector2i> &p_override) { } bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); diff --git a/scene/resources/text_line.h b/scene/resources/text_line.h index 6ed3558bd9..74d4f2c32c 100644 --- a/scene/resources/text_line.h +++ b/scene/resources/text_line.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -45,7 +45,7 @@ class TextLine : public Reference { bool dirty = true; - float width = -1; + float width = -1.0; uint8_t flags = TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA; HAlign align = HALIGN_LEFT; diff --git a/scene/resources/text_paragraph.cpp b/scene/resources/text_paragraph.cpp index fd6dd071eb..012d36cc35 100644 --- a/scene/resources/text_paragraph.cpp +++ b/scene/resources/text_paragraph.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -55,6 +55,9 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextParagraph::_set_bidi_override); + ClassDB::bind_method(D_METHOD("set_dropcap", "text", "fonts", "size", "dropcap_margins", "opentype_features", "language"), &TextParagraph::set_dropcap, DEFVAL(Rect2()), DEFVAL(Dictionary()), DEFVAL("")); + ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap); + ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL("")); ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1)); ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(VALIGN_CENTER)); @@ -81,6 +84,7 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("get_rid"), &TextParagraph::get_rid); ClassDB::bind_method(D_METHOD("get_line_rid", "line"), &TextParagraph::get_line_rid); + ClassDB::bind_method(D_METHOD("get_dropcap_rid"), &TextParagraph::get_dropcap_rid); ClassDB::bind_method(D_METHOD("get_line_count"), &TextParagraph::get_line_count); @@ -94,12 +98,21 @@ void TextParagraph::_bind_methods() { ClassDB::bind_method(D_METHOD("get_line_underline_position", "line"), &TextParagraph::get_line_underline_position); ClassDB::bind_method(D_METHOD("get_line_underline_thickness", "line"), &TextParagraph::get_line_underline_thickness); - ClassDB::bind_method(D_METHOD("draw", "canvas", "pos", "color"), &TextParagraph::draw, DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "outline_size", "color"), &TextParagraph::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("get_spacing_top"), &TextParagraph::get_spacing_top); + ClassDB::bind_method(D_METHOD("get_spacing_bottom"), &TextParagraph::get_spacing_bottom); + + ClassDB::bind_method(D_METHOD("get_dropcap_size"), &TextParagraph::get_dropcap_size); + ClassDB::bind_method(D_METHOD("get_dropcap_lines"), &TextParagraph::get_dropcap_lines); + + ClassDB::bind_method(D_METHOD("draw", "canvas", "pos", "color", "dc_color"), &TextParagraph::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_outline", "canvas", "pos", "outline_size", "color", "dc_color"), &TextParagraph::draw_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1)), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_line", "canvas", "pos", "line", "color"), &TextParagraph::draw_line, DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_line_outline", "canvas", "pos", "line", "outline_size", "color"), &TextParagraph::draw_line_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_dropcap", "canvas", "pos", "color"), &TextParagraph::draw_dropcap, DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("draw_dropcap_outline", "canvas", "pos", "outline_size", "color"), &TextParagraph::draw_dropcap_outline, DEFVAL(1), DEFVAL(Color(1, 1, 1))); + ClassDB::bind_method(D_METHOD("hit_test", "coords"), &TextParagraph::hit_test); } @@ -110,14 +123,50 @@ void TextParagraph::_shape_lines() { } lines.clear(); - if (!tab_stops.empty()) { + if (!tab_stops.is_empty()) { TS->shaped_text_tab_align(rid, tab_stops); } - Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width, 0, flags); + float h_offset = 0.f; + float v_offset = 0.f; + int start = 0; + dropcap_lines = 0; + + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + v_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + v_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } + + if (h_offset > 0) { + // Dropcap, flow around. + Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width - h_offset, 0, flags); + for (int i = 0; i < line_breaks.size(); i++) { + RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x); + float h = (TS->shaped_text_get_orientation(line) == TextServer::ORIENTATION_HORIZONTAL) ? TS->shaped_text_get_size(line).y : TS->shaped_text_get_size(line).x; + if (v_offset < h) { + TS->free(line); + break; + } + if (!tab_stops.is_empty()) { + TS->shaped_text_tab_align(line, tab_stops); + } + if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) { + TS->shaped_text_fit_to_width(line, width - h_offset, flags); + } + dropcap_lines++; + v_offset -= h; + start = line_breaks[i].y; + lines.push_back(line); + } + } + // Use fixed for the rest of lines. + Vector<Vector2i> line_breaks = TS->shaped_text_get_line_breaks(rid, width, start, flags); for (int i = 0; i < line_breaks.size(); i++) { RID line = TS->shaped_text_substr(rid, line_breaks[i].x, line_breaks[i].y - line_breaks[i].x); - if (!tab_stops.empty()) { + if (!tab_stops.is_empty()) { TS->shaped_text_tab_align(line, tab_stops); } if (align == HALIGN_FILL && (line_breaks.size() == 1 || i < line_breaks.size() - 1)) { @@ -139,6 +188,10 @@ RID TextParagraph::get_line_rid(int p_line) const { return lines[p_line]; } +RID TextParagraph::get_dropcap_rid() const { + return dropcap_rid; +} + void TextParagraph::clear() { spacing_top = 0; spacing_bottom = 0; @@ -147,10 +200,12 @@ void TextParagraph::clear() { } lines.clear(); TS->shaped_text_clear(rid); + TS->shaped_text_clear(dropcap_rid); } void TextParagraph::set_preserve_invalid(bool p_enabled) { TS->shaped_text_set_preserve_invalid(rid, p_enabled); + TS->shaped_text_set_preserve_invalid(dropcap_rid, p_enabled); dirty_lines = true; } @@ -160,6 +215,7 @@ bool TextParagraph::get_preserve_invalid() const { void TextParagraph::set_preserve_control(bool p_enabled) { TS->shaped_text_set_preserve_control(rid, p_enabled); + TS->shaped_text_set_preserve_control(dropcap_rid, p_enabled); dirty_lines = true; } @@ -169,6 +225,7 @@ bool TextParagraph::get_preserve_control() const { void TextParagraph::set_direction(TextServer::Direction p_direction) { TS->shaped_text_set_direction(rid, p_direction); + TS->shaped_text_set_direction(dropcap_rid, p_direction); dirty_lines = true; } @@ -179,6 +236,7 @@ TextServer::Direction TextParagraph::get_direction() const { void TextParagraph::set_orientation(TextServer::Orientation p_orientation) { TS->shaped_text_set_orientation(rid, p_orientation); + TS->shaped_text_set_orientation(dropcap_rid, p_orientation); dirty_lines = true; } @@ -187,7 +245,23 @@ TextServer::Orientation TextParagraph::get_orientation() const { return TS->shaped_text_get_orientation(rid); } +bool TextParagraph::set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); + TS->shaped_text_clear(dropcap_rid); + dropcap_margins = p_dropcap_margins; + bool res = TS->shaped_text_add_string(dropcap_rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); + dirty_lines = true; + return res; +} + +void TextParagraph::clear_dropcap() { + dropcap_margins = Rect2(); + TS->shaped_text_clear(dropcap_rid); + dirty_lines = true; +} + bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { + ERR_FAIL_COND_V(p_fonts.is_null(), false); bool res = TS->shaped_text_add_string(rid, p_text, p_fonts->get_rids(), p_size, p_opentype_features, p_language); spacing_top = p_fonts->get_spacing(Font::SPACING_TOP); spacing_bottom = p_fonts->get_spacing(Font::SPACING_BOTTOM); @@ -195,6 +269,14 @@ bool TextParagraph::add_string(const String &p_text, const Ref<Font> &p_fonts, i return res; } +int TextParagraph::get_spacing_top() const { + return spacing_top; +} + +int TextParagraph::get_spacing_bottom() const { + return spacing_bottom; +} + void TextParagraph::_set_bidi_override(const Array &p_override) { Vector<Vector2i> overrides; for (int i = 0; i < p_override.size(); i++) { @@ -359,16 +441,57 @@ float TextParagraph::get_line_underline_thickness(int p_line) const { return TS->shaped_text_get_underline_thickness(lines[p_line]); } -void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const { +Size2 TextParagraph::get_dropcap_size() const { + return TS->shaped_text_get_size(dropcap_rid) + dropcap_margins.size + dropcap_margins.position; +} + +int TextParagraph::get_dropcap_lines() const { + return dropcap_lines; +} + +void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color, const Color &p_dc_color) const { const_cast<TextParagraph *>(this)->_shape_lines(); Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + Vector2 dc_off = ofs; + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + dc_off.x += width - h_offset; + } else { + dc_off.y += width - h_offset; + } + } + TS->shaped_text_draw(dropcap_rid, p_canvas, dc_off + Vector2(0, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.size.y + dropcap_margins.position.y / 2), -1, -1, p_dc_color); + } + for (int i = 0; i < lines.size(); i++) { + float l_width = width; if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } } else { ofs.y = p_pos.y; ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } } float length = TS->shaped_text_get_width(lines[i]); if (width > 0) { @@ -378,16 +501,16 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo break; case HALIGN_CENTER: { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.x += Math::floor((width - length) / 2.0); + ofs.x += Math::floor((l_width - length) / 2.0); } else { - ofs.y += Math::floor((width - length) / 2.0); + ofs.y += Math::floor((l_width - length) / 2.0); } } break; case HALIGN_RIGHT: { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.x += width - length; + ofs.x += l_width - length; } else { - ofs.y += width - length; + ofs.y += l_width - length; } } break; } @@ -398,7 +521,7 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo } else { clip_l = MAX(0, p_pos.y - ofs.y); } - TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_color); + TS->shaped_text_draw(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_color); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; @@ -409,16 +532,50 @@ void TextParagraph::draw(RID p_canvas, const Vector2 &p_pos, const Color &p_colo } } -void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const { +void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color, const Color &p_dc_color) const { const_cast<TextParagraph *>(this)->_shape_lines(); Vector2 ofs = p_pos; + + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + Vector2 dc_off = ofs; + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + dc_off.x += width - h_offset; + } else { + dc_off.y += width - h_offset; + } + } + TS->shaped_text_draw_outline(dropcap_rid, p_canvas, dc_off + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_dc_color); + } + for (int i = 0; i < lines.size(); i++) { + float l_width = width; if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; ofs.y += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } } else { ofs.y = p_pos.y; ofs.x += TS->shaped_text_get_ascent(lines[i]) + spacing_top; + if (i <= dropcap_lines) { + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_LTR) { + ofs.x -= h_offset; + } + l_width -= h_offset; + } } float length = TS->shaped_text_get_width(lines[i]); if (width > 0) { @@ -428,16 +585,16 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli break; case HALIGN_CENTER: { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.x += Math::floor((width - length) / 2.0); + ofs.x += Math::floor((l_width - length) / 2.0); } else { - ofs.y += Math::floor((width - length) / 2.0); + ofs.y += Math::floor((l_width - length) / 2.0); } } break; case HALIGN_RIGHT: { if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { - ofs.x += width - length; + ofs.x += l_width - length; } else { - ofs.y += width - length; + ofs.y += l_width - length; } } break; } @@ -448,7 +605,7 @@ void TextParagraph::draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outli } else { clip_l = MAX(0, p_pos.y - ofs.y); } - TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + width, p_outline_size, p_color); + TS->shaped_text_draw_outline(lines[i], p_canvas, ofs, clip_l, clip_l + l_width, p_outline_size, p_color); if (TS->shaped_text_get_orientation(lines[i]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.x = p_pos.x; ofs.y += TS->shaped_text_get_descent(lines[i]) + spacing_bottom; @@ -485,11 +642,56 @@ int TextParagraph::hit_test(const Point2 &p_coords) const { return TS->shaped_text_get_range(rid).y; } +void TextParagraph::draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color) const { + Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - h_offset; + } else { + ofs.y += width - h_offset; + } + } + TS->shaped_text_draw(dropcap_rid, p_canvas, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_color); + } +} + +void TextParagraph::draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size, const Color &p_color) const { + Vector2 ofs = p_pos; + float h_offset = 0.f; + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + h_offset = TS->shaped_text_get_size(dropcap_rid).x + dropcap_margins.size.x + dropcap_margins.position.x; + } else { + h_offset = TS->shaped_text_get_size(dropcap_rid).y + dropcap_margins.size.y + dropcap_margins.position.y; + } + + if (h_offset > 0) { + // Draw dropcap. + if (TS->shaped_text_get_direction(dropcap_rid) == TextServer::DIRECTION_RTL) { + if (TS->shaped_text_get_orientation(dropcap_rid) == TextServer::ORIENTATION_HORIZONTAL) { + ofs.x += width - h_offset; + } else { + ofs.y += width - h_offset; + } + } + TS->shaped_text_draw_outline(dropcap_rid, p_canvas, ofs + Vector2(dropcap_margins.position.x, TS->shaped_text_get_ascent(dropcap_rid) + dropcap_margins.position.y), -1, -1, p_outline_size, p_color); + } +} + void TextParagraph::draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color) const { const_cast<TextParagraph *>(this)->_shape_lines(); ERR_FAIL_COND(p_line < 0 || p_line >= lines.size()); Vector2 ofs = p_pos; + if (TS->shaped_text_get_orientation(lines[p_line]) == TextServer::ORIENTATION_HORIZONTAL) { ofs.y += TS->shaped_text_get_ascent(lines[p_line]) + spacing_top; } else { @@ -521,6 +723,7 @@ TextParagraph::TextParagraph(const String &p_text, const Ref<Font> &p_fonts, int TextParagraph::TextParagraph() { rid = TS->create_shaped_text(); + dropcap_rid = TS->create_shaped_text(); } TextParagraph::~TextParagraph() { @@ -529,4 +732,5 @@ TextParagraph::~TextParagraph() { } lines.clear(); TS->free(rid); + TS->free(dropcap_rid); } diff --git a/scene/resources/text_paragraph.h b/scene/resources/text_paragraph.h index f7f49e9058..4396b07130 100644 --- a/scene/resources/text_paragraph.h +++ b/scene/resources/text_paragraph.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -39,6 +39,10 @@ class TextParagraph : public Reference { GDCLASS(TextParagraph, Reference); + RID dropcap_rid; + int dropcap_lines = 0; + Rect2 dropcap_margins; + RID rid; Vector<RID> lines; int spacing_top = 0; @@ -46,7 +50,7 @@ class TextParagraph : public Reference { bool dirty_lines = true; - float width = -1; + float width = -1.0; uint8_t flags = TextServer::BREAK_MANDATORY | TextServer::BREAK_WORD_BOUND | TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA; HAlign align = HALIGN_LEFT; @@ -60,6 +64,7 @@ protected: public: RID get_rid() const; RID get_line_rid(int p_line) const; + RID get_dropcap_rid() const; void clear(); @@ -77,6 +82,9 @@ public: void set_bidi_override(const Vector<Vector2i> &p_override); + bool set_dropcap(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); + void clear_dropcap(); + bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = ""); bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1); bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER); @@ -108,12 +116,21 @@ public: float get_line_underline_position(int p_line) const; float get_line_underline_thickness(int p_line) const; - void draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1)) const; - void draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + int get_spacing_top() const; + int get_spacing_bottom() const; + + Size2 get_dropcap_size() const; + int get_dropcap_lines() const; + + void draw(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1)) const; + void draw_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1), const Color &p_dc_color = Color(1, 1, 1)) const; void draw_line(RID p_canvas, const Vector2 &p_pos, int p_line, const Color &p_color = Color(1, 1, 1)) const; void draw_line_outline(RID p_canvas, const Vector2 &p_pos, int p_line, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + void draw_dropcap(RID p_canvas, const Vector2 &p_pos, const Color &p_color = Color(1, 1, 1)) const; + void draw_dropcap_outline(RID p_canvas, const Vector2 &p_pos, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + int hit_test(const Point2 &p_coords) const; void _set_bidi_override(const Array &p_override); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 706b18d2b5..b6a2f24b8b 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,7 +71,7 @@ void Texture2D::_bind_methods() { 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); + ClassDB::bind_method(D_METHOD("get_image"), &Texture2D::get_image); ADD_GROUP("", ""); } @@ -94,7 +94,7 @@ void ImageTexture::reload_from_file() { create_from_image(img); } else { Resource::reload_from_file(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -116,7 +116,7 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) { bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const { if (p_name == "image") { - r_ret = get_data(); + r_ret = get_image(); } else if (p_name == "size") { r_ret = Size2(w, h); } else { @@ -146,12 +146,12 @@ void ImageTexture::_reload_hook(const RID &p_hook) { RID new_texture = RenderingServer::get_singleton()->texture_2d_create(img); RenderingServer::get_singleton()->texture_replace(texture, new_texture); - _change_notify(); + notify_property_list_changed(); emit_changed(); } void ImageTexture::create_from_image(const Ref<Image> &p_image) { - ERR_FAIL_COND_MSG(p_image.is_null(), "Invalid image"); + ERR_FAIL_COND_MSG(p_image.is_null() || p_image->is_empty(), "Invalid image"); w = p_image->get_width(); h = p_image->get_height(); format = p_image->get_format(); @@ -163,7 +163,7 @@ void ImageTexture::create_from_image(const Ref<Image> &p_image) { RID new_texture = RenderingServer::get_singleton()->texture_2d_create(p_image); RenderingServer::get_singleton()->texture_replace(texture, new_texture); } - _change_notify(); + notify_property_list_changed(); emit_changed(); image_stored = true; @@ -189,7 +189,7 @@ void ImageTexture::update(const Ref<Image> &p_image, bool p_immediate) { RenderingServer::get_singleton()->texture_2d_update(texture, p_image); } - _change_notify(); + notify_property_list_changed(); emit_changed(); alpha_cache.unref(); @@ -200,7 +200,7 @@ void ImageTexture::_resource_path_changed() { String path = get_path(); } -Ref<Image> ImageTexture::get_data() const { +Ref<Image> ImageTexture::get_image() const { if (image_stored) { return RenderingServer::get_singleton()->texture_2d_get(texture); } else { @@ -251,7 +251,7 @@ void ImageTexture::draw_rect_region(RID p_canvas_item, const Rect2 &p_rect, cons bool ImageTexture::is_pixel_opaque(int p_x, int p_y) const { if (!alpha_cache.is_valid()) { - Ref<Image> img = get_data(); + Ref<Image> img = get_image(); if (img.is_valid()) { if (img->is_compressed()) { //must decompress, if compressed Ref<Image> decom = img->duplicate(); @@ -310,12 +310,7 @@ void ImageTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook); } -ImageTexture::ImageTexture() { - w = h = 0; - image_stored = false; - mipmaps = false; - format = Image::FORMAT_L8; -} +ImageTexture::ImageTexture() {} ImageTexture::~ImageTexture() { if (texture.is_valid()) { @@ -371,8 +366,8 @@ Ref<Image> StreamTexture2D::load_image_from_file(FileAccess *f, int p_size_limit img = Image::lossy_unpacker(pv); } - if (img.is_null() || img->empty()) { - ERR_FAIL_COND_V(img.is_null() || img->empty(), Ref<Image>()); + if (img.is_null() || img->is_empty()) { + ERR_FAIL_COND_V(img.is_null() || img->is_empty(), Ref<Image>()); } if (first) { @@ -548,7 +543,7 @@ Error StreamTexture2D::_load_data(const String &p_path, int &tw, int &th, int &t memdelete(f); - if (image.is_null() || image->empty()) { + if (image.is_null() || image->is_empty()) { return ERR_CANT_OPEN; } @@ -617,7 +612,7 @@ Error StreamTexture2D::load(const String &p_path) { } #endif - _change_notify(); + notify_property_list_changed(); emit_changed(); return OK; } @@ -666,7 +661,7 @@ bool StreamTexture2D::has_alpha() const { return false; } -Ref<Image> StreamTexture2D::get_data() const { +Ref<Image> StreamTexture2D::get_image() const { if (texture.is_valid()) { return RS::get_singleton()->texture_2d_get(texture); } else { @@ -676,7 +671,7 @@ Ref<Image> StreamTexture2D::get_data() const { bool StreamTexture2D::is_pixel_opaque(int p_x, int p_y) const { if (!alpha_cache.is_valid()) { - Ref<Image> img = get_data(); + Ref<Image> img = get_image(); if (img.is_valid()) { if (img->is_compressed()) { //must decompress, if compressed Ref<Image> decom = img->duplicate(); @@ -733,11 +728,7 @@ void StreamTexture2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "load_path", PROPERTY_HINT_FILE, "*.stex"), "load", "get_load_path"); } -StreamTexture2D::StreamTexture2D() { - format = Image::FORMAT_MAX; - w = 0; - h = 0; -} +StreamTexture2D::StreamTexture2D() {} StreamTexture2D::~StreamTexture2D() { if (texture.is_valid()) { @@ -745,7 +736,7 @@ StreamTexture2D::~StreamTexture2D() { } } -RES ResourceFormatLoaderStreamTexture2D::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) { +RES ResourceFormatLoaderStreamTexture2D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTexture2D> st; st.instance(); Error err = st->load(p_path); @@ -924,7 +915,7 @@ Error StreamTexture3D::_load_data(const String &p_path, Vector<Ref<Image>> &r_da 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); + ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); if (i == 0) { r_format = image->get_format(); r_width = image->get_width(); @@ -968,7 +959,7 @@ Error StreamTexture3D::load(const String &p_path) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } - _change_notify(); + notify_property_list_changed(); emit_changed(); return OK; } @@ -1033,13 +1024,7 @@ void StreamTexture3D::_bind_methods() { 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() {} StreamTexture3D::~StreamTexture3D() { if (texture.is_valid()) { @@ -1049,7 +1034,7 @@ StreamTexture3D::~StreamTexture3D() { ///////////////////////////// -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) { +RES ResourceFormatLoaderStreamTexture3D::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTexture3D> st; st.instance(); Error err = st->load(p_path); @@ -1125,7 +1110,6 @@ void AtlasTexture::set_atlas(const Ref<Texture2D> &p_atlas) { } atlas = p_atlas; emit_changed(); - _change_notify("atlas"); } Ref<Texture2D> AtlasTexture::get_atlas() const { @@ -1138,7 +1122,6 @@ void AtlasTexture::set_region(const Rect2 &p_region) { } region = p_region; emit_changed(); - _change_notify("region"); } Rect2 AtlasTexture::get_region() const { @@ -1151,7 +1134,6 @@ void AtlasTexture::set_margin(const Rect2 &p_margin) { } margin = p_margin; emit_changed(); - _change_notify("margin"); } Rect2 AtlasTexture::get_margin() const { @@ -1161,7 +1143,6 @@ Rect2 AtlasTexture::get_margin() const { void AtlasTexture::set_filter_clip(const bool p_enable) { filter_clip = p_enable; emit_changed(); - _change_notify("filter_clip"); } bool AtlasTexture::has_filter_clip() const { @@ -1295,9 +1276,7 @@ bool AtlasTexture::is_pixel_opaque(int p_x, int p_y) const { return atlas->is_pixel_opaque(x, y); } -AtlasTexture::AtlasTexture() { - filter_clip = false; -} +AtlasTexture::AtlasTexture() {} ///////////////////////////////////////// @@ -1516,7 +1495,7 @@ Ref<Texture2D> LargeTexture::get_piece_texture(int p_idx) const { Ref<Image> LargeTexture::to_image() const { Ref<Image> img = memnew(Image(this->get_width(), this->get_height(), false, Image::FORMAT_RGBA8)); for (int i = 0; i < pieces.size(); i++) { - Ref<Image> src_img = pieces[i].texture->get_data(); + Ref<Image> src_img = pieces[i].texture->get_image(); img->blit_rect(src_img, Rect2(0, 0, src_img->get_width(), src_img->get_height()), pieces[i].offset); } @@ -1698,9 +1677,7 @@ RID CurveTexture::get_rid() const { return _texture; } -CurveTexture::CurveTexture() { - _width = 2048; -} +CurveTexture::CurveTexture() {} CurveTexture::~CurveTexture() { if (_texture.is_valid()) { @@ -1711,9 +1688,6 @@ CurveTexture::~CurveTexture() { ////////////////// GradientTexture::GradientTexture() { - update_pending = false; - width = 2048; - _queue_update(); } @@ -1808,7 +1782,7 @@ int GradientTexture::get_width() const { return width; } -Ref<Image> GradientTexture::get_data() const { +Ref<Image> GradientTexture::get_image() const { if (!texture.is_valid()) { return Ref<Image>(); } @@ -1926,7 +1900,7 @@ void AnimatedTexture::_update_proxy() { } } time -= frame_limit; - _change_notify("current_frame"); + } else { break; } @@ -2057,14 +2031,14 @@ bool AnimatedTexture::has_alpha() const { return frames[current_frame].texture->has_alpha(); } -Ref<Image> AnimatedTexture::get_data() const { +Ref<Image> AnimatedTexture::get_image() const { RWLockRead r(rw_lock); if (!frames[current_frame].texture.is_valid()) { return Ref<Image>(); } - return frames[current_frame].texture->get_data(); + return frames[current_frame].texture->get_image(); } bool AnimatedTexture::is_pixel_opaque(int p_x, int p_y) const { @@ -2128,28 +2102,12 @@ AnimatedTexture::AnimatedTexture() { proxy = RS::get_singleton()->texture_proxy_create(proxy_ph); RenderingServer::get_singleton()->texture_set_force_redraw_if_visible(proxy, true); - time = 0; - frame_count = 1; - fps = 4; - prev_ticks = 0; - current_frame = 0; - pause = false; - oneshot = false; RenderingServer::get_singleton()->connect("frame_pre_draw", callable_mp(this, &AnimatedTexture::_update_proxy)); - -#ifndef NO_THREADS - rw_lock = RWLock::create(); -#else - rw_lock = nullptr; -#endif } AnimatedTexture::~AnimatedTexture() { RS::get_singleton()->free(proxy); RS::get_singleton()->free(proxy_ph); - if (rw_lock) { - memdelete(rw_lock); - } } /////////////////////////////// @@ -2223,7 +2181,7 @@ Error ImageTextureLayered::create_from_images(Vector<Ref<Image>> p_images) { "Cubemap array layers must be a multiple of 6"); } - ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->empty(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(p_images[0].is_null() || p_images[0]->is_empty(), ERR_INVALID_PARAMETER); Image::Format new_format = p_images[0]->get_format(); int new_width = p_images[0]->get_width(); @@ -2297,11 +2255,6 @@ void ImageTextureLayered::_bind_methods() { ImageTextureLayered::ImageTextureLayered(LayeredType p_layered_type) { layered_type = p_layered_type; - format = Image::FORMAT_MAX; - - width = 0; - height = 0; - layers = 0; } ImageTextureLayered::~ImageTextureLayered() { @@ -2361,7 +2314,7 @@ Error StreamTextureLayered::_load_data(const String &p_path, Vector<Ref<Image>> for (uint32_t i = 0; i < layer_count; i++) { Ref<Image> image = StreamTexture2D::load_image_from_file(f, p_size_limit); - ERR_FAIL_COND_V(image.is_null() || image->empty(), ERR_CANT_OPEN); + ERR_FAIL_COND_V(image.is_null() || image->is_empty(), ERR_CANT_OPEN); images.write[i] = image; } @@ -2398,7 +2351,7 @@ Error StreamTextureLayered::load(const String &p_path) { RenderingServer::get_singleton()->texture_set_path(texture, p_path); } - _change_notify(); + notify_property_list_changed(); emit_changed(); return OK; } @@ -2469,11 +2422,6 @@ void StreamTextureLayered::_bind_methods() { StreamTextureLayered::StreamTextureLayered(LayeredType p_type) { layered_type = p_type; - format = Image::FORMAT_MAX; - w = 0; - h = 0; - layers = 0; - mipmaps = false; } StreamTextureLayered::~StreamTextureLayered() { @@ -2484,7 +2432,7 @@ StreamTextureLayered::~StreamTextureLayered() { ///////////////////////////////////////////////// -RES ResourceFormatLoaderStreamTextureLayered::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) { +RES ResourceFormatLoaderStreamTextureLayered::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { Ref<StreamTextureLayered> st; if (p_path.get_extension().to_lower() == "stexarray") { Ref<StreamTexture2DArray> s; @@ -2595,14 +2543,14 @@ uint32_t CameraTexture::get_flags() const { return 0; } -Ref<Image> CameraTexture::get_data() const { +Ref<Image> CameraTexture::get_image() const { // not (yet) supported return Ref<Image>(); } void CameraTexture::set_camera_feed_id(int p_new_id) { camera_feed_id = p_new_id; - _change_notify(); + notify_property_list_changed(); } int CameraTexture::get_camera_feed_id() const { @@ -2611,7 +2559,7 @@ int CameraTexture::get_camera_feed_id() const { void CameraTexture::set_which_feed(CameraServer::FeedImage p_which) { which_feed = p_which; - _change_notify(); + notify_property_list_changed(); } CameraServer::FeedImage CameraTexture::get_which_feed() const { @@ -2622,7 +2570,7 @@ void CameraTexture::set_camera_active(bool p_active) { Ref<CameraFeed> feed = CameraServer::get_singleton()->get_feed_by_id(camera_feed_id); if (feed.is_valid()) { feed->set_active(p_active); - _change_notify(); + notify_property_list_changed(); } } @@ -2635,10 +2583,7 @@ bool CameraTexture::get_camera_active() const { } } -CameraTexture::CameraTexture() { - camera_feed_id = 0; - which_feed = CameraServer::FEED_RGBA_IMAGE; -} +CameraTexture::CameraTexture() {} CameraTexture::~CameraTexture() { // nothing to do here yet diff --git a/scene/resources/texture.h b/scene/resources/texture.h index a8d8b785fa..16c98f2891 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -71,7 +71,7 @@ public: 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>(); } + virtual Ref<Image> get_image() const { return Ref<Image>(); } Texture2D(); }; @@ -83,12 +83,13 @@ class ImageTexture : public Texture2D { RES_BASE_EXTENSION("tex"); mutable RID texture; - Image::Format format; - bool mipmaps; - int w, h; + Image::Format format = Image::FORMAT_L8; + bool mipmaps = false; + int w = 0; + int h = 0; Size2 size_override; mutable Ref<BitMap> alpha_cache; - bool image_stored; + bool image_stored = false; protected: virtual void reload_from_file() override; @@ -107,7 +108,7 @@ public: Image::Format get_format() const; void update(const Ref<Image> &p_image, bool p_immediate = false); - Ref<Image> get_data() const override; + Ref<Image> get_image() const override; int get_width() const override; int get_height() const override; @@ -160,8 +161,9 @@ private: Error _load_data(const String &p_path, int &tw, int &th, int &tw_custom, int &th_custom, Ref<Image> &image, bool &r_request_3d, bool &r_request_normal, bool &r_request_roughness, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format; - int w, h; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; mutable Ref<BitMap> alpha_cache; virtual void reload_from_file() override; @@ -201,7 +203,7 @@ public: virtual bool has_alpha() const override; bool is_pixel_opaque(int p_x, int p_y) const override; - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; StreamTexture2D(); ~StreamTexture2D(); @@ -209,7 +211,7 @@ public: class ResourceFormatLoaderStreamTexture2D : 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 RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual 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; @@ -223,7 +225,7 @@ protected: Ref<Texture2D> atlas; Rect2 region; Rect2 margin; - bool filter_clip; + bool filter_clip = false; static void _bind_methods(); @@ -370,12 +372,12 @@ class ImageTextureLayered : public TextureLayered { LayeredType layered_type; mutable RID texture; - Image::Format format; + Image::Format format = Image::FORMAT_MAX; - int width; - int height; - int layers; - bool mipmaps; + int width = 0; + int height = 0; + int layers = 0; + bool mipmaps = false; Error _create_from_images(const Array &p_images); @@ -453,10 +455,12 @@ private: Error _load_data(const String &p_path, Vector<Ref<Image>> &images, int &mipmap_limit, int p_size_limit = 0); String path_to_file; mutable RID texture; - Image::Format format; - int w, h, layers; - bool mipmaps; - LayeredType layered_type; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; + int layers = 0; + bool mipmaps = false; + LayeredType layered_type = LayeredType::LAYERED_TYPE_2D_ARRAY; virtual void reload_from_file() override; @@ -509,7 +513,7 @@ public: class ResourceFormatLoaderStreamTextureLayered : 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 RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual 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; @@ -594,9 +598,11 @@ 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; + Image::Format format = Image::FORMAT_MAX; + int w = 0; + int h = 0; + int d = 0; + bool mipmaps = false; virtual void reload_from_file() override; @@ -625,7 +631,7 @@ public: 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 RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); virtual 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; @@ -638,7 +644,7 @@ class CurveTexture : public Texture2D { private: mutable RID _texture; Ref<Curve> _curve; - int _width; + int _width = 2048; void _update(); @@ -680,7 +686,7 @@ class GradientTexture : public Texture2D { public: struct Point { - float offset; + float offset = 0.0; Color color; bool operator<(const Point &p_ponit) const { return offset < p_ponit.offset; @@ -689,9 +695,9 @@ public: private: Ref<Gradient> gradient; - bool update_pending; + bool update_pending = false; RID texture; - int width; + int width = 2048; void _queue_update(); void _update(); @@ -710,7 +716,7 @@ public: virtual int get_height() const override { return 1; } virtual bool has_alpha() const override { return true; } - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; GradientTexture(); virtual ~GradientTexture(); @@ -745,7 +751,7 @@ class AnimatedTexture : public Texture2D { GDCLASS(AnimatedTexture, Texture2D); //use readers writers lock for this, since its far more times read than written to - RWLock *rw_lock; + RWLock rw_lock; public: enum { @@ -758,23 +764,19 @@ private: struct Frame { Ref<Texture2D> texture; - float delay_sec; - - Frame() { - delay_sec = 0; - } + float delay_sec = 0.0; }; Frame frames[MAX_FRAMES]; - int frame_count; - int current_frame; - bool pause; - bool oneshot; - float fps; + int frame_count = 1.0; + int current_frame = 0; + bool pause = false; + bool oneshot = false; + float fps = 4.0; - float time; + float time = 0.0; - uint64_t prev_ticks; + uint64_t prev_ticks = 0; void _update_proxy(); @@ -810,7 +812,7 @@ public: virtual bool has_alpha() const override; - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; bool is_pixel_opaque(int p_x, int p_y) const override; @@ -822,8 +824,8 @@ class CameraTexture : public Texture2D { GDCLASS(CameraTexture, Texture2D); private: - int camera_feed_id; - CameraServer::FeedImage which_feed; + int camera_feed_id = 0; + CameraServer::FeedImage which_feed = CameraServer::FEED_RGBA_IMAGE; protected: static void _bind_methods(); @@ -837,7 +839,7 @@ public: virtual void set_flags(uint32_t p_flags); virtual uint32_t get_flags() const; - virtual Ref<Image> get_data() const override; + virtual Ref<Image> get_image() const override; void set_camera_feed_id(int p_new_id); int get_camera_feed_id() const; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index c8bfcdfab4..036d11574c 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -141,6 +141,21 @@ Vector<String> Theme::_get_font_size_list(const String &p_node_type) const { return ilret; } +Vector<String> Theme::_get_font_size_type_list() const { + Vector<String> ilret; + List<StringName> il; + + get_font_size_type_list(&il); + ilret.resize(il.size()); + + int i = 0; + String *w = ilret.ptrw(); + for (List<StringName>::Element *E = il.front(); E; E = E->next(), i++) { + w[i] = E->get(); + } + return ilret; +} + Vector<String> Theme::_get_color_list(const String &p_node_type) const { Vector<String> ilret; List<StringName> il; @@ -201,6 +216,48 @@ Vector<String> Theme::_get_constant_type_list() const { return ilret; } +Vector<String> Theme::_get_theme_item_list(DataType p_data_type, const String &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_list(p_node_type); + case DATA_TYPE_CONSTANT: + return _get_constant_list(p_node_type); + case DATA_TYPE_FONT: + return _get_font_list(p_node_type); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_list(p_node_type); + case DATA_TYPE_ICON: + return _get_icon_list(p_node_type); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_list(p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + +Vector<String> Theme::_get_theme_item_type_list(DataType p_data_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return _get_color_type_list(); + case DATA_TYPE_CONSTANT: + return _get_constant_type_list(); + case DATA_TYPE_FONT: + return _get_font_type_list(); + case DATA_TYPE_FONT_SIZE: + return _get_font_size_type_list(); + case DATA_TYPE_ICON: + return _get_icon_type_list(); + case DATA_TYPE_STYLEBOX: + return _get_stylebox_type_list(); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Vector<String>(); +} + Vector<String> Theme::_get_type_list() const { Vector<String> ilret; List<StringName> il; @@ -358,7 +415,7 @@ void Theme::set_default_theme_font(const Ref<Font> &p_default_font) { default_theme_font->connect("changed", callable_mp(this, &Theme::_emit_theme_changed), varray(), CONNECT_REFERENCE_COUNTED); } - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -373,7 +430,7 @@ void Theme::set_default_theme_font_size(int p_font_size) { default_theme_font_size = p_font_size; - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -421,8 +478,6 @@ void Theme::set_default_font_size(int p_font_size) { } 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_node_type) || !icon_map[p_node_type].has(p_name); if (icon_map[p_node_type].has(p_name) && icon_map[p_node_type][p_name].is_valid()) { @@ -436,7 +491,7 @@ void Theme::set_icon(const StringName &p_name, const StringName &p_node_type, co } if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -453,9 +508,21 @@ bool Theme::has_icon(const StringName &p_name, const StringName &p_node_type) co 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::rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot rename the icon '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(icon_map[p_node_type].has(p_name), "Cannot rename the icon '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_old_name), "Cannot rename the icon '" + String(p_old_name) + "' because it does not exist."); + + icon_map[p_node_type][p_name] = icon_map[p_node_type][p_old_name]; + icon_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + 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)); + ERR_FAIL_COND_MSG(!icon_map.has(p_node_type), "Cannot clear the icon '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!icon_map[p_node_type].has(p_name), "Cannot clear the icon '" + String(p_name) + "' because it does not exist."); 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)); @@ -463,7 +530,7 @@ void Theme::clear_icon(const StringName &p_name, const StringName &p_node_type) icon_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -481,6 +548,10 @@ void Theme::get_icon_list(StringName p_node_type, List<StringName> *p_list) cons } } +void Theme::add_icon_type(const StringName &p_node_type) { + icon_map[p_node_type] = HashMap<StringName, Ref<Texture2D>>(); +} + void Theme::get_icon_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -491,8 +562,6 @@ void Theme::get_icon_type_list(List<StringName> *p_list) const { } 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_node_type) || !style_map[p_node_type].has(p_name); if (style_map[p_node_type].has(p_name) && style_map[p_node_type][p_name].is_valid()) { @@ -506,7 +575,7 @@ void Theme::set_stylebox(const StringName &p_name, const StringName &p_node_type } if (new_value) { - _change_notify(); + notify_property_list_changed(); } emit_changed(); } @@ -523,9 +592,21 @@ bool Theme::has_stylebox(const StringName &p_name, const StringName &p_node_type 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::rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot rename the stylebox '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(style_map[p_node_type].has(p_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_old_name), "Cannot rename the stylebox '" + String(p_old_name) + "' because it does not exist."); + + style_map[p_node_type][p_name] = style_map[p_node_type][p_old_name]; + style_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + 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)); + ERR_FAIL_COND_MSG(!style_map.has(p_node_type), "Cannot clear the stylebox '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!style_map[p_node_type].has(p_name), "Cannot clear the stylebox '" + String(p_name) + "' because it does not exist."); 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)); @@ -533,7 +614,7 @@ void Theme::clear_stylebox(const StringName &p_name, const StringName &p_node_ty style_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -551,6 +632,10 @@ void Theme::get_stylebox_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_stylebox_type(const StringName &p_node_type) { + style_map[p_node_type] = HashMap<StringName, Ref<StyleBox>>(); +} + void Theme::get_stylebox_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -561,8 +646,6 @@ void Theme::get_stylebox_type_list(List<StringName> *p_list) const { } 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_node_type) || !font_map[p_node_type].has(p_name); if (font_map[p_node_type][p_name].is_valid()) { @@ -576,7 +659,7 @@ void Theme::set_font(const StringName &p_name, const StringName &p_node_type, co } if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -595,16 +678,28 @@ bool Theme::has_font(const StringName &p_name, const StringName &p_node_type) co return ((font_map.has(p_node_type) && font_map[p_node_type].has(p_name) && font_map[p_node_type][p_name].is_valid()) || default_theme_font.is_valid()); } +void Theme::rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot rename the font '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_map[p_node_type].has(p_name), "Cannot rename the font '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_old_name), "Cannot rename the font '" + String(p_old_name) + "' because it does not exist."); + + font_map[p_node_type][p_name] = font_map[p_node_type][p_old_name]; + font_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + 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)); + ERR_FAIL_COND_MSG(!font_map.has(p_node_type), "Cannot clear the font '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_map[p_node_type].has(p_name), "Cannot clear the font '" + String(p_name) + "' because it does not exist."); 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_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -622,6 +717,10 @@ void Theme::get_font_list(StringName p_node_type, List<StringName> *p_list) cons } } +void Theme::add_font_type(const StringName &p_node_type) { + font_map[p_node_type] = HashMap<StringName, Ref<Font>>(); +} + void Theme::get_font_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -637,7 +736,7 @@ void Theme::set_font_size(const StringName &p_name, const StringName &p_node_typ font_size_map[p_node_type][p_name] = p_font_size; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -656,12 +755,24 @@ bool Theme::has_font_size(const StringName &p_name, const StringName &p_node_typ return ((font_size_map.has(p_node_type) && font_size_map[p_node_type].has(p_name) && (font_size_map[p_node_type][p_name] > 0)) || (default_theme_font_size > 0)); } +void Theme::rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot rename the font size '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(font_size_map[p_node_type].has(p_name), "Cannot rename the font size '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_old_name), "Cannot rename the font size '" + String(p_old_name) + "' because it does not exist."); + + font_size_map[p_node_type][p_name] = font_size_map[p_node_type][p_old_name]; + font_size_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + void Theme::clear_font_size(const StringName &p_name, const StringName &p_node_type) { - ERR_FAIL_COND(!font_size_map.has(p_node_type)); - ERR_FAIL_COND(!font_size_map[p_node_type].has(p_name)); + ERR_FAIL_COND_MSG(!font_size_map.has(p_node_type), "Cannot clear the font size '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!font_size_map[p_node_type].has(p_name), "Cannot clear the font size '" + String(p_name) + "' because it does not exist."); font_size_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -679,13 +790,26 @@ void Theme::get_font_size_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_font_size_type(const StringName &p_node_type) { + font_size_map[p_node_type] = HashMap<StringName, int>(); +} + +void Theme::get_font_size_type_list(List<StringName> *p_list) const { + ERR_FAIL_NULL(p_list); + + const StringName *key = nullptr; + while ((key = font_size_map.next(key))) { + p_list->push_back(*key); + } +} + 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_node_type][p_name] = p_color; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -702,12 +826,24 @@ bool Theme::has_color(const StringName &p_name, const StringName &p_node_type) c return (color_map.has(p_node_type) && color_map[p_node_type].has(p_name)); } +void Theme::rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot rename the color '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(color_map[p_node_type].has(p_name), "Cannot rename the color '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_old_name), "Cannot rename the color '" + String(p_old_name) + "' because it does not exist."); + + color_map[p_node_type][p_name] = color_map[p_node_type][p_old_name]; + color_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + 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)); + ERR_FAIL_COND_MSG(!color_map.has(p_node_type), "Cannot clear the color '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!color_map[p_node_type].has(p_name), "Cannot clear the color '" + String(p_name) + "' because it does not exist."); color_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -725,6 +861,10 @@ void Theme::get_color_list(StringName p_node_type, List<StringName> *p_list) con } } +void Theme::add_color_type(const StringName &p_node_type) { + color_map[p_node_type] = HashMap<StringName, Color>(); +} + void Theme::get_color_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -739,7 +879,7 @@ void Theme::set_constant(const StringName &p_name, const StringName &p_node_type constant_map[p_node_type][p_name] = p_constant; if (new_value) { - _change_notify(); + notify_property_list_changed(); emit_changed(); } } @@ -756,12 +896,24 @@ bool Theme::has_constant(const StringName &p_name, const StringName &p_node_type return (constant_map.has(p_node_type) && constant_map[p_node_type].has(p_name)); } +void Theme::rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot rename the constant '" + String(p_old_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(constant_map[p_node_type].has(p_name), "Cannot rename the constant '" + String(p_old_name) + "' because the new name '" + String(p_name) + "' already exists."); + ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_old_name), "Cannot rename the constant '" + String(p_old_name) + "' because it does not exist."); + + constant_map[p_node_type][p_name] = constant_map[p_node_type][p_old_name]; + constant_map[p_node_type].erase(p_old_name); + + notify_property_list_changed(); + emit_changed(); +} + 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)); + ERR_FAIL_COND_MSG(!constant_map.has(p_node_type), "Cannot clear the constant '" + String(p_name) + "' because the node type '" + String(p_node_type) + "' does not exist."); + ERR_FAIL_COND_MSG(!constant_map[p_node_type].has(p_name), "Cannot clear the constant '" + String(p_name) + "' because it does not exist."); constant_map[p_node_type].erase(p_name); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -779,6 +931,10 @@ void Theme::get_constant_list(StringName p_node_type, List<StringName> *p_list) } } +void Theme::add_constant_type(const StringName &p_node_type) { + constant_map[p_node_type] = HashMap<StringName, int>(); +} + void Theme::get_constant_type_list(List<StringName> *p_list) const { ERR_FAIL_NULL(p_list); @@ -788,6 +944,216 @@ void Theme::get_constant_type_list(List<StringName> *p_list) const { } } +void Theme::set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value) { + switch (p_data_type) { + case DATA_TYPE_COLOR: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::COLOR, "Theme item's data type (Color) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Color color_value = p_value; + set_color(p_name, p_node_type, color_value); + } break; + case DATA_TYPE_CONSTANT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int constant_value = p_value; + set_constant(p_name, p_node_type, constant_value); + } break; + case DATA_TYPE_FONT: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<Font> font_value = Object::cast_to<Font>(p_value.get_validated_object()); + set_font(p_name, p_node_type, font_value); + } break; + case DATA_TYPE_FONT_SIZE: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::INT, "Theme item's data type (int) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + int font_size_value = p_value; + set_font_size(p_name, p_node_type, font_size_value); + } break; + case DATA_TYPE_ICON: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<Texture2D> icon_value = Object::cast_to<Texture2D>(p_value.get_validated_object()); + set_icon(p_name, p_node_type, icon_value); + } break; + case DATA_TYPE_STYLEBOX: { + ERR_FAIL_COND_MSG(p_value.get_type() != Variant::OBJECT, "Theme item's data type (Object) does not match Variant's type (" + Variant::get_type_name(p_value.get_type()) + ")."); + + Ref<StyleBox> stylebox_value = Object::cast_to<StyleBox>(p_value.get_validated_object()); + set_stylebox(p_name, p_node_type, stylebox_value); + } break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +Variant Theme::get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return get_color(p_name, p_node_type); + case DATA_TYPE_CONSTANT: + return get_constant(p_name, p_node_type); + case DATA_TYPE_FONT: + return get_font(p_name, p_node_type); + case DATA_TYPE_FONT_SIZE: + return get_font_size(p_name, p_node_type); + case DATA_TYPE_ICON: + return get_icon(p_name, p_node_type); + case DATA_TYPE_STYLEBOX: + return get_stylebox(p_name, p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return Variant(); +} + +bool Theme::has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + return has_color(p_name, p_node_type); + case DATA_TYPE_CONSTANT: + return has_constant(p_name, p_node_type); + case DATA_TYPE_FONT: + return has_font(p_name, p_node_type); + case DATA_TYPE_FONT_SIZE: + return has_font_size(p_name, p_node_type); + case DATA_TYPE_ICON: + return has_icon(p_name, p_node_type); + case DATA_TYPE_STYLEBOX: + return has_stylebox(p_name, p_node_type); + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } + + return false; +} + +void Theme::rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + rename_color(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_CONSTANT: + rename_constant(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_FONT: + rename_font(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + rename_font_size(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_ICON: + rename_icon(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_STYLEBOX: + rename_stylebox(p_old_name, p_name, p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + clear_color(p_name, p_node_type); + break; + case DATA_TYPE_CONSTANT: + clear_constant(p_name, p_node_type); + break; + case DATA_TYPE_FONT: + clear_font(p_name, p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + clear_font_size(p_name, p_node_type); + break; + case DATA_TYPE_ICON: + clear_icon(p_name, p_node_type); + break; + case DATA_TYPE_STYLEBOX: + clear_stylebox(p_name, p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_list(p_node_type, p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_list(p_node_type, p_list); + break; + case DATA_TYPE_FONT: + get_font_list(p_node_type, p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_list(p_node_type, p_list); + break; + case DATA_TYPE_ICON: + get_icon_list(p_node_type, p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_list(p_node_type, p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::add_theme_item_type(DataType p_data_type, const StringName &p_node_type) { + switch (p_data_type) { + case DATA_TYPE_COLOR: + add_color_type(p_node_type); + break; + case DATA_TYPE_CONSTANT: + add_constant_type(p_node_type); + break; + case DATA_TYPE_FONT: + add_font_type(p_node_type); + break; + case DATA_TYPE_FONT_SIZE: + add_font_size_type(p_node_type); + break; + case DATA_TYPE_ICON: + add_icon_type(p_node_type); + break; + case DATA_TYPE_STYLEBOX: + add_stylebox_type(p_node_type); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + +void Theme::get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const { + switch (p_data_type) { + case DATA_TYPE_COLOR: + get_color_type_list(p_list); + break; + case DATA_TYPE_CONSTANT: + get_constant_type_list(p_list); + break; + case DATA_TYPE_FONT: + get_font_type_list(p_list); + break; + case DATA_TYPE_FONT_SIZE: + get_font_size_type_list(p_list); + break; + case DATA_TYPE_ICON: + get_icon_type_list(p_list); + break; + case DATA_TYPE_STYLEBOX: + get_stylebox_type_list(p_list); + break; + case DATA_TYPE_MAX: + break; // Can't happen, but silences warning. + } +} + void Theme::clear() { //these need disconnecting { @@ -835,7 +1201,7 @@ void Theme::clear() { color_map.clear(); constant_map.clear(); - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -847,11 +1213,10 @@ void Theme::copy_default_theme() { void Theme::copy_theme(const Ref<Theme> &p_other) { if (p_other.is_null()) { clear(); - return; } - //these need reconnecting, so add normally + // These items need reconnecting, so add them normally. { const StringName *K = nullptr; while ((K = p_other->icon_map.next(K))) { @@ -882,12 +1247,12 @@ void Theme::copy_theme(const Ref<Theme> &p_other) { } } - //these are ok to just copy - + // These items can be simply copied. + font_size_map = p_other->font_size_map; color_map = p_other->color_map; constant_map = p_other->constant_map; - _change_notify(); + notify_property_list_changed(); emit_changed(); } @@ -930,10 +1295,14 @@ void Theme::get_type_list(List<StringName> *p_list) const { } } +void Theme::reset_state() { + clear(); +} void Theme::_bind_methods() { 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("rename_icon", "old_name", "name", "node_type"), &Theme::rename_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("get_icon_type_list"), &Theme::_get_icon_type_list); @@ -941,6 +1310,7 @@ void Theme::_bind_methods() { 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("rename_stylebox", "old_name", "name", "node_type"), &Theme::rename_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_type_list"), &Theme::_get_stylebox_type_list); @@ -948,6 +1318,7 @@ void Theme::_bind_methods() { 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("rename_font", "old_name", "name", "node_type"), &Theme::rename_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("get_font_type_list"), &Theme::_get_font_type_list); @@ -955,12 +1326,15 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_font_size", "name", "node_type", "font_size"), &Theme::set_font_size); ClassDB::bind_method(D_METHOD("get_font_size", "name", "node_type"), &Theme::get_font_size); ClassDB::bind_method(D_METHOD("has_font_size", "name", "node_type"), &Theme::has_font_size); + ClassDB::bind_method(D_METHOD("rename_font_size", "old_name", "name", "node_type"), &Theme::rename_font_size); ClassDB::bind_method(D_METHOD("clear_font_size", "name", "node_type"), &Theme::clear_font_size); ClassDB::bind_method(D_METHOD("get_font_size_list", "node_type"), &Theme::_get_font_size_list); + ClassDB::bind_method(D_METHOD("get_font_size_type_list"), &Theme::_get_font_size_type_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("rename_color", "old_name", "name", "node_type"), &Theme::rename_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("get_color_type_list"), &Theme::_get_color_type_list); @@ -968,6 +1342,7 @@ void Theme::_bind_methods() { 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("rename_constant", "old_name", "name", "node_type"), &Theme::rename_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("get_constant_type_list"), &Theme::_get_constant_type_list); @@ -980,6 +1355,14 @@ void Theme::_bind_methods() { ClassDB::bind_method(D_METHOD("set_default_font_size", "font_size"), &Theme::set_default_theme_font_size); ClassDB::bind_method(D_METHOD("get_default_font_size"), &Theme::get_default_theme_font_size); + ClassDB::bind_method(D_METHOD("set_theme_item", "data_type", "name", "node_type", "value"), &Theme::set_theme_item); + ClassDB::bind_method(D_METHOD("get_theme_item", "data_type", "name", "node_type"), &Theme::get_theme_item); + ClassDB::bind_method(D_METHOD("has_theme_item", "data_type", "name", "node_type"), &Theme::has_theme_item); + ClassDB::bind_method(D_METHOD("rename_theme_item", "data_type", "old_name", "name", "node_type"), &Theme::rename_theme_item); + ClassDB::bind_method(D_METHOD("clear_theme_item", "data_type", "name", "node_type"), &Theme::clear_theme_item); + ClassDB::bind_method(D_METHOD("get_theme_item_list", "data_type", "node_type"), &Theme::_get_theme_item_list); + ClassDB::bind_method(D_METHOD("get_theme_item_type_list", "data_type"), &Theme::_get_theme_item_type_list); + ClassDB::bind_method(D_METHOD("get_type_list"), &Theme::_get_type_list); ClassDB::bind_method("copy_default_theme", &Theme::copy_default_theme); @@ -987,6 +1370,14 @@ void Theme::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "default_font", PROPERTY_HINT_RESOURCE_TYPE, "Font"), "set_default_font", "get_default_font"); ADD_PROPERTY(PropertyInfo(Variant::INT, "default_font_size"), "set_default_font_size", "get_default_font_size"); + + BIND_ENUM_CONSTANT(DATA_TYPE_COLOR); + BIND_ENUM_CONSTANT(DATA_TYPE_CONSTANT); + BIND_ENUM_CONSTANT(DATA_TYPE_FONT); + BIND_ENUM_CONSTANT(DATA_TYPE_FONT_SIZE); + BIND_ENUM_CONSTANT(DATA_TYPE_ICON); + BIND_ENUM_CONSTANT(DATA_TYPE_STYLEBOX); + BIND_ENUM_CONSTANT(DATA_TYPE_MAX); } Theme::Theme() { diff --git a/scene/resources/theme.h b/scene/resources/theme.h index ad05e0e2f5..eb918fac69 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -41,6 +41,18 @@ class Theme : public Resource { GDCLASS(Theme, Resource); RES_BASE_EXTENSION("theme"); +public: + enum DataType { + DATA_TYPE_COLOR, + DATA_TYPE_CONSTANT, + DATA_TYPE_FONT, + DATA_TYPE_FONT_SIZE, + DATA_TYPE_ICON, + DATA_TYPE_STYLEBOX, + DATA_TYPE_MAX + }; + +private: void _emit_theme_changed(); HashMap<StringName, HashMap<StringName, Ref<Texture2D>>> icon_map; @@ -57,10 +69,14 @@ class Theme : public Resource { Vector<String> _get_font_list(const String &p_node_type) const; Vector<String> _get_font_type_list() const; Vector<String> _get_font_size_list(const String &p_node_type) const; + Vector<String> _get_font_size_type_list() const; Vector<String> _get_color_list(const String &p_node_type) const; Vector<String> _get_color_type_list() const; Vector<String> _get_constant_list(const String &p_node_type) const; Vector<String> _get_constant_type_list() const; + + Vector<String> _get_theme_item_list(DataType p_data_type, const String &p_node_type) const; + Vector<String> _get_theme_item_type_list(DataType p_data_type) const; Vector<String> _get_type_list() const; protected: @@ -80,6 +96,8 @@ protected: static void _bind_methods(); + virtual void reset_state() override; + public: static Ref<Theme> get_default(); static void set_default(const Ref<Theme> &p_default); @@ -101,44 +119,66 @@ public: 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 rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); 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 add_icon_type(const StringName &p_node_type); void get_icon_type_list(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 rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); 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 add_stylebox_type(const StringName &p_node_type); void get_stylebox_type_list(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 rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); 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 add_font_type(const StringName &p_node_type); void get_font_type_list(List<StringName> *p_list) const; void set_font_size(const StringName &p_name, const StringName &p_node_type, int p_font_size); int get_font_size(const StringName &p_name, const StringName &p_node_type) const; bool has_font_size(const StringName &p_name, const StringName &p_node_type) const; + void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); void clear_font_size(const StringName &p_name, const StringName &p_node_type); void get_font_size_list(StringName p_node_type, List<StringName> *p_list) const; + void add_font_size_type(const StringName &p_node_type); + void get_font_size_type_list(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 rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); 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 add_color_type(const StringName &p_node_type); void get_color_type_list(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 rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); 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 add_constant_type(const StringName &p_node_type); void get_constant_type_list(List<StringName> *p_list) const; + void set_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type, const Variant &p_value); + Variant get_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const; + bool has_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type) const; + void rename_theme_item(DataType p_data_type, const StringName &p_old_name, const StringName &p_name, const StringName &p_node_type); + void clear_theme_item(DataType p_data_type, const StringName &p_name, const StringName &p_node_type); + void get_theme_item_list(DataType p_data_type, StringName p_node_type, List<StringName> *p_list) const; + void add_theme_item_type(DataType p_data_type, const StringName &p_node_type); + void get_theme_item_type_list(DataType p_data_type, List<StringName> *p_list) const; + void get_type_list(List<StringName> *p_list) const; void copy_default_theme(); @@ -149,4 +189,6 @@ public: ~Theme(); }; +VARIANT_ENUM_CAST(Theme::DataType); + #endif diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 4581763e9c..84be69d0d6 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -369,14 +369,14 @@ void TileSet::create_tile(int p_id) { ERR_FAIL_COND(tile_map.has(p_id)); tile_map[p_id] = TileData(); tile_map[p_id].autotile_data = AutotileData(); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].autotile_data.bitmask_mode = p_mode; - _change_notify(""); + notify_property_list_changed(); emit_changed(); } @@ -389,7 +389,6 @@ void TileSet::tile_set_texture(int p_id, const Ref<Texture2D> &p_texture) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].texture = p_texture; emit_changed(); - _change_notify("texture"); } Ref<Texture2D> TileSet::tile_get_texture(int p_id) const { @@ -412,7 +411,6 @@ void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].modulate = p_modulate; emit_changed(); - _change_notify("modulate"); } Color TileSet::tile_get_modulate(int p_id) const { @@ -435,7 +433,6 @@ void TileSet::tile_set_region(int p_id, const Rect2 &p_region) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].region = p_region; emit_changed(); - _change_notify("region"); } Rect2 TileSet::tile_get_region(int p_id) const { @@ -447,7 +444,6 @@ void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].tile_mode = p_tile_mode; emit_changed(); - _change_notify("tile_mode"); } TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const { @@ -669,7 +665,6 @@ void TileSet::tile_set_name(int p_id, const String &p_name) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map[p_id].name = p_name; emit_changed(); - _change_notify("name"); } String TileSet::tile_get_name(int p_id) const { @@ -1060,7 +1055,7 @@ bool TileSet::is_tile_bound(int p_drawn_id, int p_neighbor_id) { void TileSet::remove_tile(int p_id) { ERR_FAIL_COND(!tile_map.has(p_id)); tile_map.erase(p_id); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } @@ -1081,9 +1076,13 @@ int TileSet::find_tile_by_name(const String &p_name) const { return -1; } +void TileSet::reset_state() { + clear(); +} + void TileSet::clear() { tile_map.clear(); - _change_notify(""); + notify_property_list_changed(); emit_changed(); } diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index 79f1b4aa95..0a8721f35b 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -136,6 +136,8 @@ protected: static void _bind_methods(); + virtual void reset_state() override; + public: void create_tile(int p_id); diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h index 379ba53a34..f960f85521 100644 --- a/scene/resources/video_stream.h +++ b/scene/resources/video_stream.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 34129e35da..859546694f 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -33,6 +33,7 @@ #include "core/templates/vmap.h" #include "servers/rendering/shader_types.h" #include "visual_shader_nodes.h" +#include "visual_shader_sdf_nodes.h" bool VisualShaderNode::is_simple_decl() const { return simple_decl; @@ -486,6 +487,22 @@ void VisualShader::remove_node(Type p_type, int p_id) { _queue_update(); } +void VisualShader::replace_node(Type p_type, int p_id, const StringName &p_new_class) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); + ERR_FAIL_COND(p_id < 2); + Graph *g = &graph[p_type]; + ERR_FAIL_COND(!g->nodes.has(p_id)); + + if (g->nodes[p_id].node->get_class_name() == p_new_class) { + return; + } + VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(p_new_class)); + vsn->connect("changed", callable_mp(this, &VisualShader::_queue_update)); + g->nodes[p_id].node = Ref<VisualShaderNode>(vsn); + + _queue_update(); +} + bool VisualShader::is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const { ERR_FAIL_INDEX_V(p_type, TYPE_MAX, false); const Graph *g = &graph[p_type]; @@ -568,6 +585,12 @@ bool VisualShader::is_port_types_compatible(int p_a, int p_b) const { void VisualShader::connect_nodes_forced(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) { ERR_FAIL_INDEX(p_type, TYPE_MAX); Graph *g = &graph[p_type]; + + ERR_FAIL_COND(!g->nodes.has(p_from_node)); + ERR_FAIL_INDEX(p_from_port, g->nodes[p_from_node].node->get_output_port_count()); + ERR_FAIL_COND(!g->nodes.has(p_to_node)); + ERR_FAIL_INDEX(p_to_port, g->nodes[p_to_node].node->get_input_port_count()); + Connection c; c.from_node = p_from_node; c.from_port = p_from_port; @@ -658,6 +681,8 @@ void VisualShader::get_node_connections(Type p_type, List<Connection> *r_connect } void VisualShader::set_mode(Mode p_mode) { + ERR_FAIL_INDEX_MSG(p_mode, Mode::MODE_MAX, vformat("Invalid shader mode: %d.", p_mode)); + if (shader_mode == p_mode) { return; } @@ -713,7 +738,7 @@ void VisualShader::set_mode(Mode p_mode) { } _queue_update(); - _change_notify(); + notify_property_list_changed(); } void VisualShader::set_graph_offset(const Vector2 &p_offset) { @@ -1078,6 +1103,12 @@ bool VisualShader::_get(const StringName &p_name, Variant &r_ret) const { return false; } +void VisualShader::reset_state() { +#ifndef _MSC_VER +#warning everything needs to be cleared here +#endif + emit_changed(); +} void VisualShader::_get_property_list(List<PropertyInfo> *p_list) const { //mode p_list->push_back(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Node3D,CanvasItem,Particles,Sky")); @@ -1375,11 +1406,11 @@ bool VisualShader::has_func_name(RenderingServer::ShaderMode p_mode, const Strin } void VisualShader::_update_shader() const { - if (!dirty) { + if (!dirty.is_set()) { return; } - dirty = false; + dirty.clear(); StringBuilder global_code; StringBuilder global_code_per_node; @@ -1565,15 +1596,16 @@ void VisualShader::_update_shader() const { } void VisualShader::_queue_update() { - if (dirty) { + if (dirty.is_set()) { return; } - dirty = true; + dirty.set(); call_deferred("_update_shader"); } void VisualShader::_input_type_changed(Type p_type, int p_id) { + ERR_FAIL_INDEX(p_type, TYPE_MAX); //erase connections using this input, as type changed Graph *g = &graph[p_type]; @@ -1588,7 +1620,7 @@ void VisualShader::_input_type_changed(Type p_type, int p_id) { } void VisualShader::rebuild() { - dirty = true; + dirty.set(); _update_shader(); } @@ -1605,6 +1637,7 @@ void VisualShader::_bind_methods() { ClassDB::bind_method(D_METHOD("get_valid_node_id", "type"), &VisualShader::get_valid_node_id); ClassDB::bind_method(D_METHOD("remove_node", "type", "id"), &VisualShader::remove_node); + ClassDB::bind_method(D_METHOD("replace_node", "type", "id", "new_class"), &VisualShader::replace_node); ClassDB::bind_method(D_METHOD("is_node_connection", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::is_node_connection); ClassDB::bind_method(D_METHOD("can_connect_nodes", "type", "from_node", "from_port", "to_node", "to_port"), &VisualShader::can_connect_nodes); @@ -1641,6 +1674,7 @@ void VisualShader::_bind_methods() { } VisualShader::VisualShader() { + dirty.set(); for (int i = 0; i < TYPE_MAX; i++) { Ref<VisualShaderNodeOutput> output; output.instance(); @@ -2359,8 +2393,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, - { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" }, { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" }, @@ -2386,8 +2420,8 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = { { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "color", "COLOR.rgb" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "COLOR.a" }, { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal", "NORMAL" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normalmap", "NORMALMAP" }, - { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normalmap_depth", "NORMALMAP_DEPTH" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR, "normal_map", "NORMAL_MAP" }, + { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" }, // 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" }, @@ -3124,7 +3158,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad _expression = _expression.replace("\n", "\n\t\t"); static Vector<String> pre_symbols; - if (pre_symbols.empty()) { + if (pre_symbols.is_empty()) { pre_symbols.push_back("\t"); pre_symbols.push_back(","); pre_symbols.push_back(";"); @@ -3144,7 +3178,7 @@ String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShad } static Vector<String> post_symbols; - if (post_symbols.empty()) { + if (post_symbols.is_empty()) { post_symbols.push_back("\t"); post_symbols.push_back("\n"); post_symbols.push_back(","); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index a38c2886e2..ef724c7650 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -32,6 +32,7 @@ #define VISUAL_SHADER_H #include "core/string/string_builder.h" +#include "core/templates/safe_refcount.h" #include "scene/gui/control.h" #include "scene/resources/shader.h" @@ -57,10 +58,10 @@ public: }; struct Connection { - int from_node; - int from_port; - int to_node; - int to_port; + int from_node = 0; + int from_port = 0; + int to_node = 0; + int to_port = 0; }; struct DefaultTextureParam { @@ -90,7 +91,7 @@ private: Vector2 graph_offset; struct RenderModeEnums { - Shader::Mode mode; + Shader::Mode mode = Shader::Mode::MODE_MAX; const char *string; }; @@ -99,7 +100,7 @@ private: static RenderModeEnums render_mode_enums[]; - volatile mutable bool dirty = true; + mutable SafeFlag dirty; void _queue_update(); union ConnectionKey { @@ -107,7 +108,7 @@ private: uint64_t node : 32; uint64_t port : 32; }; - uint64_t key; + uint64_t key = 0; bool operator<(const ConnectionKey &p_key) const { return key < p_key.key; } @@ -126,6 +127,8 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; void _get_property_list(List<PropertyInfo> *p_list) const; + virtual void reset_state() override; + public: // internal methods void set_shader_type(Type p_type); Type get_shader_type() const; @@ -152,6 +155,7 @@ public: int find_node_id(Type p_type, const Ref<VisualShaderNode> &p_node) const; void remove_node(Type p_type, int p_id); + void replace_node(Type p_type, int p_id, const StringName &p_new_class); bool is_node_connection(Type p_type, int p_from_node, int p_from_port, int p_to_node, int p_to_port) const; @@ -264,7 +268,7 @@ class VisualShaderNodeCustom : public VisualShaderNode { struct Port { String name; - int type; + int type = 0; }; List<Port> input_ports; @@ -304,9 +308,9 @@ class VisualShaderNodeInput : public VisualShaderNode { Shader::Mode shader_mode = Shader::MODE_MAX; struct Port { - Shader::Mode mode; - VisualShader::Type shader_type; - PortType type; + Shader::Mode mode = Shader::Mode::MODE_MAX; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + PortType type = PortType::PORT_TYPE_MAX; const char *name; const char *string; }; @@ -355,13 +359,13 @@ class VisualShaderNodeOutput : public VisualShaderNode { public: friend class VisualShader; - VisualShader::Type shader_type; - Shader::Mode shader_mode; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + Shader::Mode shader_mode = Shader::Mode::MODE_MAX; struct Port { - Shader::Mode mode; - VisualShader::Type shader_type; - PortType type; + Shader::Mode mode = Shader::Mode::MODE_MAX; + VisualShader::Type shader_type = VisualShader::Type::TYPE_MAX; + PortType type = PortType::PORT_TYPE_MAX; const char *name; const char *string; }; @@ -518,7 +522,7 @@ protected: bool editable = false; struct Port { - PortType type; + PortType type = PortType::PORT_TYPE_MAX; String name; }; diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index a3358ea8c7..a99c09e89c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -30,6 +30,11 @@ #include "visual_shader_nodes.h" +////////////// Constants Base + +VisualShaderNodeConstant::VisualShaderNodeConstant() { +} + ////////////// Scalar(Float) String VisualShaderNodeFloatConstant::get_caption() const { @@ -480,7 +485,7 @@ String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShade case TYPE_COLOR: u += " : hint_albedo"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: u += " : hint_normal"; break; } @@ -780,7 +785,7 @@ void VisualShaderNodeTexture::_bind_methods() { BIND_ENUM_CONSTANT(SOURCE_PORT); BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); } VisualShaderNodeTexture::VisualShaderNodeTexture() { @@ -1181,7 +1186,7 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade case TYPE_COLOR: u += " : hint_albedo"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: u += " : hint_normal"; break; } @@ -1310,7 +1315,7 @@ void VisualShaderNodeCubemap::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); } VisualShaderNodeCubemap::VisualShaderNodeCubemap() { @@ -2081,9 +2086,6 @@ String VisualShaderNodeIntFunc::get_caption() const { } int VisualShaderNodeIntFunc::get_input_port_count() const { - if (func == FUNC_CLAMP) { - return 3; - } return 1; } @@ -2092,15 +2094,6 @@ VisualShaderNodeIntFunc::PortType VisualShaderNodeIntFunc::get_input_port_type(i } String VisualShaderNodeIntFunc::get_input_port_name(int p_port) const { - if (func == FUNC_CLAMP) { - if (p_port == 0) { - return ""; - } else if (p_port == 1) { - return "min"; - } else if (p_port == 2) { - return "max"; - } - } return ""; } @@ -2117,13 +2110,8 @@ String VisualShaderNodeIntFunc::get_output_port_name(int p_port) const { } String VisualShaderNodeIntFunc::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 (func == FUNC_CLAMP) { - return "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; - } - static const char *int_func_id[FUNC_SIGN + 1] = { "abs($)", - "", "-($)", "sign($)" }; @@ -2132,12 +2120,6 @@ String VisualShaderNodeIntFunc::generate_code(Shader::Mode p_mode, VisualShader: } void VisualShaderNodeIntFunc::set_function(Function p_func) { - if (func != p_func) { - if (p_func == FUNC_CLAMP) { - set_input_port_default_value(1, 0); - set_input_port_default_value(2, 0); - } - } func = p_func; emit_changed(); } @@ -2156,10 +2138,9 @@ void VisualShaderNodeIntFunc::_bind_methods() { ClassDB::bind_method(D_METHOD("set_function", "func"), &VisualShaderNodeIntFunc::set_function); ClassDB::bind_method(D_METHOD("get_function"), &VisualShaderNodeIntFunc::get_function); - ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Clamp,Negate,Sign"), "set_function", "get_function"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "function", PROPERTY_HINT_ENUM, "Abs,Negate,Sign"), "set_function", "get_function"); BIND_ENUM_CONSTANT(FUNC_ABS); - BIND_ENUM_CONSTANT(FUNC_CLAMP); BIND_ENUM_CONSTANT(FUNC_NEGATE); BIND_ENUM_CONSTANT(FUNC_SIGN); } @@ -2749,21 +2730,29 @@ VisualShaderNodeVectorDerivativeFunc::VisualShaderNodeVectorDerivativeFunc() { set_input_port_default_value(0, Vector3()); } -////////////// Scalar Clamp +////////////// Clamp -String VisualShaderNodeScalarClamp::get_caption() const { - return "ScalarClamp"; +String VisualShaderNodeClamp::get_caption() const { + return "Clamp"; } -int VisualShaderNodeScalarClamp::get_input_port_count() const { +int VisualShaderNodeClamp::get_input_port_count() const { return 3; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_input_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { +String VisualShaderNodeClamp::get_input_port_name(int p_port) const { if (p_port == 0) { return ""; } else if (p_port == 1) { @@ -2774,73 +2763,84 @@ String VisualShaderNodeScalarClamp::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeScalarClamp::get_output_port_count() const { +int VisualShaderNodeClamp::get_output_port_count() const { return 1; } -VisualShaderNodeScalarClamp::PortType VisualShaderNodeScalarClamp::get_output_port_type(int p_port) const { +VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarClamp::get_output_port_name(int p_port) const { +String VisualShaderNodeClamp::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeScalarClamp::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 VisualShaderNodeClamp::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 "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeScalarClamp::VisualShaderNodeScalarClamp() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 1.0); -} - -////////////// Vector Clamp - -String VisualShaderNodeVectorClamp::get_caption() const { - return "VectorClamp"; -} - -int VisualShaderNodeVectorClamp::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorClamp::get_input_port_name(int p_port) const { - if (p_port == 0) { - return ""; - } else if (p_port == 1) { - return "min"; - } else if (p_port == 2) { - return "max"; +void VisualShaderNodeClamp::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; } - return ""; + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(0, 0); + set_input_port_default_value(1, 0); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorClamp::get_output_port_count() const { - return 1; +VisualShaderNodeClamp::OpType VisualShaderNodeClamp::get_op_type() const { + return op_type; } -VisualShaderNodeVectorClamp::PortType VisualShaderNodeVectorClamp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +Vector<StringName> VisualShaderNodeClamp::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -String VisualShaderNodeVectorClamp::get_output_port_name(int p_port) const { - return ""; -} +void VisualShaderNodeClamp::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeClamp::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeClamp::get_op_type); -String VisualShaderNodeVectorClamp::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 "\t" + p_output_vars[0] + " = clamp(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorClamp::VisualShaderNodeVectorClamp() { - set_input_port_default_value(0, Vector3(0, 0, 0)); - set_input_port_default_value(1, Vector3(0, 0, 0)); - set_input_port_default_value(2, Vector3(1, 1, 1)); +VisualShaderNodeClamp::VisualShaderNodeClamp() { + set_input_port_default_value(0, 0.0); + set_input_port_default_value(1, 0.0); + set_input_port_default_value(2, 1.0); } ////////////// FaceForward @@ -2938,24 +2938,32 @@ VisualShaderNodeOuterProduct::VisualShaderNodeOuterProduct() { set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); } -////////////// Vector-Scalar Step +////////////// Step -String VisualShaderNodeVectorScalarStep::get_caption() const { - return "VectorScalarStep"; +String VisualShaderNodeStep::get_caption() const { + return "Step"; } -int VisualShaderNodeVectorScalarStep::get_input_port_count() const { +int VisualShaderNodeStep::get_input_port_count() const { return 2; } -VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_SCALAR; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + if (p_port == 1) { + return PORT_TYPE_VECTOR; + } + break; + default: + break; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { +String VisualShaderNodeStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge"; } else if (p_port == 1) { @@ -2964,89 +2972,120 @@ String VisualShaderNodeVectorScalarStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorScalarStep::get_output_port_count() const { +int VisualShaderNodeStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorScalarStep::PortType VisualShaderNodeVectorScalarStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorScalarStep::get_output_port_name(int p_port) const { +String VisualShaderNodeStep::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeVectorScalarStep::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 "\t" + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; -} - -VisualShaderNodeVectorScalarStep::VisualShaderNodeVectorScalarStep() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); -} - -////////////// Scalar SmoothStep - -String VisualShaderNodeScalarSmoothStep::get_caption() const { - return "ScalarSmoothStep"; -} - -int VisualShaderNodeScalarSmoothStep::get_input_port_count() const { - return 3; +void VisualShaderNodeStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(1, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x + } + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_SCALAR; +VisualShaderNodeStep::OpType VisualShaderNodeStep::get_op_type() const { + return op_type; } -String VisualShaderNodeScalarSmoothStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge0"; - } else if (p_port == 1) { - return "edge1"; - } else if (p_port == 2) { - return "x"; - } - return ""; +String VisualShaderNodeStep::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 "\t" + p_output_vars[0] + " = step(" + p_input_vars[0] + ", " + p_input_vars[1] + ");\n"; } -int VisualShaderNodeScalarSmoothStep::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeScalarSmoothStep::PortType VisualShaderNodeScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} +void VisualShaderNodeStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeStep::get_op_type); -String VisualShaderNodeScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -String VisualShaderNodeScalarSmoothStep::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 "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeScalarSmoothStep::VisualShaderNodeScalarSmoothStep() { +VisualShaderNodeStep::VisualShaderNodeStep() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, 0.0); } -////////////// Vector SmoothStep +////////////// SmoothStep -String VisualShaderNodeVectorSmoothStep::get_caption() const { - return "VectorSmoothStep"; +String VisualShaderNodeSmoothStep::get_caption() const { + return "SmoothStep"; } -int VisualShaderNodeVectorSmoothStep::get_input_port_count() const { +int VisualShaderNodeSmoothStep::get_input_port_count() const { return 3; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + if (p_port == 2) { + return PORT_TYPE_VECTOR; // x + } + break; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::get_input_port_name(int p_port) const { if (p_port == 0) { return "edge0"; } else if (p_port == 1) { @@ -3057,78 +3096,96 @@ String VisualShaderNodeVectorSmoothStep::get_input_port_name(int p_port) const { return ""; } -int VisualShaderNodeVectorSmoothStep::get_output_port_count() const { +int VisualShaderNodeSmoothStep::get_output_port_count() const { return 1; } -VisualShaderNodeVectorSmoothStep::PortType VisualShaderNodeVectorSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } + return PORT_TYPE_SCALAR; } -String VisualShaderNodeVectorSmoothStep::get_output_port_name(int p_port) const { +String VisualShaderNodeSmoothStep::get_output_port_name(int p_port) const { return ""; } -String VisualShaderNodeVectorSmoothStep::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 "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; -} - -VisualShaderNodeVectorSmoothStep::VisualShaderNodeVectorSmoothStep() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); -} - -////////////// Vector-Scalar SmoothStep - -String VisualShaderNodeVectorScalarSmoothStep::get_caption() const { - return "VectorScalarSmoothStep"; -} - -int VisualShaderNodeVectorScalarSmoothStep::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_SCALAR; - } else if (p_port == 1) { - return PORT_TYPE_SCALAR; +void VisualShaderNodeSmoothStep::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_VECTOR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, 0.0); // x + } + break; + case OP_TYPE_VECTOR: + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // edge0 + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + case OP_TYPE_VECTOR_SCALAR: + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(0, 0.0); // edge0 + set_input_port_default_value(1, 0.0); // edge1 + } + if (op_type == OP_TYPE_SCALAR) { + set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); // x + } + break; + default: + break; } - return PORT_TYPE_VECTOR; + op_type = p_op_type; + emit_changed(); } -String VisualShaderNodeVectorScalarSmoothStep::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "edge0"; - } else if (p_port == 1) { - return "edge1"; - } else if (p_port == 2) { - return "x"; - } - return ""; +VisualShaderNodeSmoothStep::OpType VisualShaderNodeSmoothStep::get_op_type() const { + return op_type; } -int VisualShaderNodeVectorScalarSmoothStep::get_output_port_count() const { - return 1; +String VisualShaderNodeSmoothStep::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 "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeVectorScalarSmoothStep::PortType VisualShaderNodeVectorScalarSmoothStep::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; +Vector<StringName> VisualShaderNodeSmoothStep::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -String VisualShaderNodeVectorScalarSmoothStep::get_output_port_name(int p_port) const { - return ""; -} +void VisualShaderNodeSmoothStep::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSmoothStep::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSmoothStep::get_op_type); -String VisualShaderNodeVectorScalarSmoothStep::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 "\t" + p_output_vars[0] + " = smoothstep(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarSmoothStep::VisualShaderNodeVectorScalarSmoothStep() { +VisualShaderNodeSmoothStep::VisualShaderNodeSmoothStep() { set_input_port_default_value(0, 0.0); set_input_port_default_value(1, 0.0); - set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); + set_input_port_default_value(2, 0.0); } ////////////// Distance @@ -3226,21 +3283,32 @@ VisualShaderNodeVectorRefract::VisualShaderNodeVectorRefract() { set_input_port_default_value(2, 0.0); } -////////////// Scalar Mix +////////////// Mix -String VisualShaderNodeScalarInterp::get_caption() const { - return "ScalarMix"; +String VisualShaderNodeMix::get_caption() const { + return "Mix"; } -int VisualShaderNodeScalarInterp::get_input_port_count() const { +int VisualShaderNodeMix::get_input_port_count() const { return 3; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_input_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + if (p_port == 2) { + break; + } + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { +String VisualShaderNodeMix::get_input_port_name(int p_port) const { if (p_port == 0) { return "a"; } else if (p_port == 1) { @@ -3250,121 +3318,90 @@ String VisualShaderNodeScalarInterp::get_input_port_name(int p_port) const { } } -int VisualShaderNodeScalarInterp::get_output_port_count() const { +int VisualShaderNodeMix::get_output_port_count() const { return 1; } -VisualShaderNodeScalarInterp::PortType VisualShaderNodeScalarInterp::get_output_port_type(int p_port) const { +VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const { + switch (op_type) { + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_VECTOR_SCALAR: + return PORT_TYPE_VECTOR; + default: + break; + } return PORT_TYPE_SCALAR; } -String VisualShaderNodeScalarInterp::get_output_port_name(int p_port) const { +String VisualShaderNodeMix::get_output_port_name(int p_port) const { return "mix"; } -String VisualShaderNodeScalarInterp::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 "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; -} - -VisualShaderNodeScalarInterp::VisualShaderNodeScalarInterp() { - set_input_port_default_value(0, 0.0); - set_input_port_default_value(1, 1.0); - set_input_port_default_value(2, 0.5); -} - -////////////// Vector Mix - -String VisualShaderNodeVectorInterp::get_caption() const { - return "VectorMix"; -} - -int VisualShaderNodeVectorInterp::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_input_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; +void VisualShaderNodeMix::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_SCALAR: + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + case OP_TYPE_VECTOR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_SCALAR || op_type == OP_TYPE_VECTOR_SCALAR) { + set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); // weight + } + break; + case OP_TYPE_VECTOR_SCALAR: + set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); // a + set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); // b + if (op_type == OP_TYPE_VECTOR) { + set_input_port_default_value(2, 0.5); // weight + } + break; + default: + break; } + op_type = p_op_type; + emit_changed(); } -int VisualShaderNodeVectorInterp::get_output_port_count() const { - return 1; -} - -VisualShaderNodeVectorInterp::PortType VisualShaderNodeVectorInterp::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorInterp::get_output_port_name(int p_port) const { - return "mix"; +VisualShaderNodeMix::OpType VisualShaderNodeMix::get_op_type() const { + return op_type; } -String VisualShaderNodeVectorInterp::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 VisualShaderNodeMix::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 "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; } -VisualShaderNodeVectorInterp::VisualShaderNodeVectorInterp() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, Vector3(0.5, 0.5, 0.5)); -} - -////////////// Vector Mix (by scalar) - -String VisualShaderNodeVectorScalarMix::get_caption() const { - return "VectorScalarMix"; -} - -int VisualShaderNodeVectorScalarMix::get_input_port_count() const { - return 3; -} - -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_input_port_type(int p_port) const { - if (p_port == 2) { - return PORT_TYPE_SCALAR; - } - return PORT_TYPE_VECTOR; -} - -String VisualShaderNodeVectorScalarMix::get_input_port_name(int p_port) const { - if (p_port == 0) { - return "a"; - } else if (p_port == 1) { - return "b"; - } else { - return "weight"; - } -} - -int VisualShaderNodeVectorScalarMix::get_output_port_count() const { - return 1; +Vector<StringName> VisualShaderNodeMix::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; } -VisualShaderNodeVectorScalarMix::PortType VisualShaderNodeVectorScalarMix::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; -} +void VisualShaderNodeMix::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeMix::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeMix::get_op_type); -String VisualShaderNodeVectorScalarMix::get_output_port_name(int p_port) const { - return "mix"; -} + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector,VectorScalar"), "set_op_type", "get_op_type"); -String VisualShaderNodeVectorScalarMix::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 "\t" + p_output_vars[0] + " = mix(" + p_input_vars[0] + ", " + p_input_vars[1] + ", " + p_input_vars[2] + ");\n"; + BIND_ENUM_CONSTANT(OP_TYPE_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR_SCALAR); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); } -VisualShaderNodeVectorScalarMix::VisualShaderNodeVectorScalarMix() { - set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); - set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0)); - set_input_port_default_value(2, 0.5); +VisualShaderNodeMix::VisualShaderNodeMix() { + set_input_port_default_value(0, 0.0); // a + set_input_port_default_value(1, 1.0); // b + set_input_port_default_value(2, 0.5); // weight } ////////////// Vector Compose @@ -4350,7 +4387,7 @@ String VisualShaderNodeTextureUniform::generate_global(Shader::Mode p_mode, Visu code += " : hint_albedo;\n"; } break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -4431,7 +4468,7 @@ void VisualShaderNodeTextureUniform::_bind_methods() { BIND_ENUM_CONSTANT(TYPE_DATA); BIND_ENUM_CONSTANT(TYPE_COLOR); - BIND_ENUM_CONSTANT(TYPE_NORMALMAP); + BIND_ENUM_CONSTANT(TYPE_NORMAL_MAP); BIND_ENUM_CONSTANT(TYPE_ANISO); BIND_ENUM_CONSTANT(COLOR_DEFAULT_WHITE); @@ -4472,9 +4509,7 @@ int VisualShaderNodeTextureUniformTriplanar::get_input_port_count() const { } VisualShaderNodeTextureUniform::PortType VisualShaderNodeTextureUniformTriplanar::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_VECTOR; - } else if (p_port == 1) { + if (p_port == 0 || p_port == 1) { return PORT_TYPE_VECTOR; } return PORT_TYPE_SCALAR; @@ -4608,7 +4643,7 @@ String VisualShaderNodeTexture2DArrayUniform::generate_global(Shader::Mode p_mod else code += " : hint_albedo;\n"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -4676,7 +4711,7 @@ String VisualShaderNodeTexture3DUniform::generate_global(Shader::Mode p_mode, Vi else code += " : hint_albedo;\n"; break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -4746,7 +4781,7 @@ String VisualShaderNodeCubemapUniform::generate_global(Shader::Mode p_mode, Visu code += " : hint_albedo;\n"; } break; - case TYPE_NORMALMAP: + case TYPE_NORMAL_MAP: code += " : hint_normal;\n"; break; case TYPE_ANISO: @@ -4842,7 +4877,7 @@ VisualShaderNodeIf::VisualShaderNodeIf() { ////////////// Switch String VisualShaderNodeSwitch::get_caption() const { - return "VectorSwitch"; + return "Switch"; } int VisualShaderNodeSwitch::get_input_port_count() const { @@ -4853,7 +4888,21 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int if (p_port == 0) { return PORT_TYPE_BOOLEAN; } - return PORT_TYPE_VECTOR; + if (p_port == 1 || p_port == 2) { + switch (op_type) { + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_input_port_name(int p_port) const { @@ -4874,13 +4923,82 @@ int VisualShaderNodeSwitch::get_output_port_count() const { } VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_VECTOR; + switch (op_type) { + case OP_TYPE_INT: + return PORT_TYPE_SCALAR_INT; + case OP_TYPE_VECTOR: + return PORT_TYPE_VECTOR; + case OP_TYPE_BOOLEAN: + return PORT_TYPE_BOOLEAN; + case OP_TYPE_TRANSFORM: + return PORT_TYPE_TRANSFORM; + default: + break; + } + return PORT_TYPE_SCALAR; } String VisualShaderNodeSwitch::get_output_port_name(int p_port) const { return "result"; } +void VisualShaderNodeSwitch::set_op_type(OpType p_op_type) { + ERR_FAIL_INDEX((int)p_op_type, OP_TYPE_MAX); + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case OP_TYPE_FLOAT: + set_input_port_default_value(1, 1.0); + set_input_port_default_value(2, 0.0); + break; + case OP_TYPE_INT: + set_input_port_default_value(1, 1); + set_input_port_default_value(2, 0); + break; + case OP_TYPE_VECTOR: + 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)); + break; + case OP_TYPE_BOOLEAN: + set_input_port_default_value(1, true); + set_input_port_default_value(2, false); + break; + case OP_TYPE_TRANSFORM: + set_input_port_default_value(1, Transform()); + set_input_port_default_value(2, Transform()); + break; + default: + break; + } + op_type = p_op_type; + emit_changed(); +} + +VisualShaderNodeSwitch::OpType VisualShaderNodeSwitch::get_op_type() const { + return op_type; +} + +Vector<StringName> VisualShaderNodeSwitch::get_editable_properties() const { + Vector<StringName> props; + props.push_back("op_type"); + return props; +} + +void VisualShaderNodeSwitch::_bind_methods() { // static + ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeSwitch::set_op_type); + ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeSwitch::get_op_type); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Float,Int,Vector,Boolean,Transform"), "set_op_type", "get_op_type"); + + BIND_ENUM_CONSTANT(OP_TYPE_FLOAT); + BIND_ENUM_CONSTANT(OP_TYPE_INT); + BIND_ENUM_CONSTANT(OP_TYPE_VECTOR); + BIND_ENUM_CONSTANT(OP_TYPE_BOOLEAN); + BIND_ENUM_CONSTANT(OP_TYPE_TRANSFORM); + BIND_ENUM_CONSTANT(OP_TYPE_MAX); +} + String VisualShaderNodeSwitch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String code; code += "\tif(" + p_input_vars[0] + ")\n"; @@ -4897,29 +5015,6 @@ 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)); -} - -////////////// Switch(scalar) - -String VisualShaderNodeScalarSwitch::get_caption() const { - return "ScalarSwitch"; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_input_port_type(int p_port) const { - if (p_port == 0) { - return PORT_TYPE_BOOLEAN; - } - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::PortType VisualShaderNodeScalarSwitch::get_output_port_type(int p_port) const { - return PORT_TYPE_SCALAR; -} - -VisualShaderNodeScalarSwitch::VisualShaderNodeScalarSwitch() { - set_input_port_default_value(0, false); set_input_port_default_value(1, 1.0); set_input_port_default_value(2, 0.0); } @@ -5106,9 +5201,6 @@ int VisualShaderNodeCompare::get_input_port_count() const { } VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(int p_port) const { - if (p_port == 2) { - return PORT_TYPE_SCALAR; - } switch (ctype) { case CTYPE_SCALAR: return PORT_TYPE_SCALAR; @@ -5120,8 +5212,9 @@ VisualShaderNodeCompare::PortType VisualShaderNodeCompare::get_input_port_type(i return PORT_TYPE_BOOLEAN; case CTYPE_TRANSFORM: return PORT_TYPE_TRANSFORM; + default: + return PORT_TYPE_SCALAR; } - return PORT_TYPE_VECTOR; } String VisualShaderNodeCompare::get_input_port_name(int p_port) const { @@ -5340,10 +5433,10 @@ int VisualShaderNodeMultiplyAdd::get_input_port_count() const { } VisualShaderNodeMultiplyAdd::PortType VisualShaderNodeMultiplyAdd::get_input_port_type(int p_port) const { - if (op_type == OP_TYPE_SCALAR) { - return PORT_TYPE_SCALAR; + if (op_type == OP_TYPE_VECTOR) { + return PORT_TYPE_VECTOR; } - return PORT_TYPE_VECTOR; + return PORT_TYPE_SCALAR; } String VisualShaderNodeMultiplyAdd::get_input_port_name(int p_port) const { @@ -5379,16 +5472,22 @@ String VisualShaderNodeMultiplyAdd::generate_code(Shader::Mode p_mode, VisualSha 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) { + if (op_type == p_op_type) { + return; + } + switch (p_op_type) { + case 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); - } else { + break; + case OP_TYPE_VECTOR: set_input_port_default_value(0, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); set_input_port_default_value(2, Vector3(0.0, 0.0, 0.0)); - } + break; + default: + break; } op_type = p_op_type; emit_changed(); diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h index 4b39c76388..a5d0fe4649 100644 --- a/scene/resources/visual_shader_nodes.h +++ b/scene/resources/visual_shader_nodes.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -37,8 +37,27 @@ /// CONSTANTS /////////////////////////////////////// -class VisualShaderNodeFloatConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNode); +class VisualShaderNodeConstant : public VisualShaderNode { + GDCLASS(VisualShaderNodeConstant, VisualShaderNode); + +public: + virtual String get_caption() const override = 0; + + virtual int get_input_port_count() const override = 0; + virtual PortType get_input_port_type(int p_port) const override = 0; + virtual String get_input_port_name(int p_port) const override = 0; + + virtual int get_output_port_count() const override = 0; + virtual PortType get_output_port_type(int p_port) const override = 0; + virtual String get_output_port_name(int p_port) const override = 0; + + 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 = 0; + + VisualShaderNodeConstant(); +}; + +class VisualShaderNodeFloatConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeFloatConstant, VisualShaderNodeConstant); float constant = 0.0f; protected: @@ -67,8 +86,8 @@ public: /////////////////////////////////////// -class VisualShaderNodeIntConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeIntConstant, VisualShaderNode); +class VisualShaderNodeIntConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeIntConstant, VisualShaderNodeConstant); int constant = 0; protected: @@ -97,8 +116,8 @@ public: /////////////////////////////////////// -class VisualShaderNodeBooleanConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNode); +class VisualShaderNodeBooleanConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeBooleanConstant, VisualShaderNodeConstant); bool constant = false; protected: @@ -127,8 +146,8 @@ public: /////////////////////////////////////// -class VisualShaderNodeColorConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeColorConstant, VisualShaderNode); +class VisualShaderNodeColorConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeColorConstant, VisualShaderNodeConstant); Color constant = Color(1, 1, 1, 1); protected: @@ -157,8 +176,8 @@ public: /////////////////////////////////////// -class VisualShaderNodeVec3Constant : public VisualShaderNode { - GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNode); +class VisualShaderNodeVec3Constant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeVec3Constant, VisualShaderNodeConstant); Vector3 constant; protected: @@ -187,8 +206,8 @@ public: /////////////////////////////////////// -class VisualShaderNodeTransformConstant : public VisualShaderNode { - GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNode); +class VisualShaderNodeTransformConstant : public VisualShaderNodeConstant { + GDCLASS(VisualShaderNodeTransformConstant, VisualShaderNodeConstant); Transform constant; protected: @@ -236,7 +255,7 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP, + TYPE_NORMAL_MAP, }; private: @@ -412,7 +431,7 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP + TYPE_NORMAL_MAP }; private: @@ -807,7 +826,6 @@ class VisualShaderNodeIntFunc : public VisualShaderNode { public: enum Function { FUNC_ABS, - FUNC_CLAMP, FUNC_NEGATE, FUNC_SIGN, }; @@ -1069,29 +1087,20 @@ public: /// CLAMP /////////////////////////////////////// -class VisualShaderNodeScalarClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarClamp, VisualShaderNode); +class VisualShaderNodeClamp : public VisualShaderNode { + GDCLASS(VisualShaderNodeClamp, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //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 - - VisualShaderNodeScalarClamp(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorClamp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorClamp, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_FLOAT; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1104,11 +1113,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() 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 - VisualShaderNodeVectorClamp(); + VisualShaderNodeClamp(); }; +VARIANT_ENUM_CAST(VisualShaderNodeClamp::OpType) + /////////////////////////////////////// /// DERIVATIVE FUNCTIONS /////////////////////////////////////// @@ -1241,8 +1257,20 @@ public: /// STEP /////////////////////////////////////// -class VisualShaderNodeVectorScalarStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarStep, VisualShaderNode); +class VisualShaderNodeStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeStep, VisualShaderNode); + +public: + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1255,38 +1283,36 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() 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 - VisualShaderNodeVectorScalarStep(); + VisualShaderNodeStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeStep::OpType) + /////////////////////////////////////// /// SMOOTHSTEP /////////////////////////////////////// -class VisualShaderNodeScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarSmoothStep, VisualShaderNode); +class VisualShaderNodeSmoothStep : public VisualShaderNode { + GDCLASS(VisualShaderNodeSmoothStep, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //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 - - VisualShaderNodeScalarSmoothStep(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorSmoothStep, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1299,32 +1325,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //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 - - VisualShaderNodeVectorSmoothStep(); -}; - -/////////////////////////////////////// - -class VisualShaderNodeVectorScalarSmoothStep : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarSmoothStep, VisualShaderNode); - -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; + void set_op_type(OpType p_type); + OpType get_op_type() const; - 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<StringName> get_editable_properties() 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 - VisualShaderNodeVectorScalarSmoothStep(); + VisualShaderNodeSmoothStep(); }; +VARIANT_ENUM_CAST(VisualShaderNodeSmoothStep::OpType) + /////////////////////////////////////// /// DISTANCE /////////////////////////////////////// @@ -1375,29 +1387,20 @@ public: /// MIX /////////////////////////////////////// -class VisualShaderNodeScalarInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeScalarInterp, VisualShaderNode); +class VisualShaderNodeMix : public VisualShaderNode { + GDCLASS(VisualShaderNodeMix, VisualShaderNode); public: - virtual String get_caption() const override; - - virtual int get_input_port_count() const override; - virtual PortType get_input_port_type(int p_port) const override; - virtual String get_input_port_name(int p_port) const override; - - virtual int get_output_port_count() const override; - virtual PortType get_output_port_type(int p_port) const override; - virtual String get_output_port_name(int p_port) const override; - - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //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 - - VisualShaderNodeScalarInterp(); -}; - -/////////////////////////////////////// + enum OpType { + OP_TYPE_SCALAR, + OP_TYPE_VECTOR, + OP_TYPE_VECTOR_SCALAR, + OP_TYPE_MAX, + }; -class VisualShaderNodeVectorInterp : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorInterp, VisualShaderNode); +protected: + OpType op_type = OP_TYPE_SCALAR; + static void _bind_methods(); public: virtual String get_caption() const override; @@ -1410,32 +1413,18 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; - virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; //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 - - VisualShaderNodeVectorInterp(); -}; - -/////////////////////////////////////// - -class VisualShaderNodeVectorScalarMix : public VisualShaderNode { - GDCLASS(VisualShaderNodeVectorScalarMix, VisualShaderNode); - -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; + void set_op_type(OpType p_type); + OpType get_op_type() const; - 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<StringName> get_editable_properties() 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 - VisualShaderNodeVectorScalarMix(); + VisualShaderNodeMix(); }; +VARIANT_ENUM_CAST(VisualShaderNodeMix::OpType) + /////////////////////////////////////// /// COMPOSE /////////////////////////////////////// @@ -1834,7 +1823,7 @@ public: enum TextureType { TYPE_DATA, TYPE_COLOR, - TYPE_NORMALMAP, + TYPE_NORMAL_MAP, TYPE_ANISO, }; @@ -2004,6 +1993,21 @@ class VisualShaderNodeSwitch : public VisualShaderNode { GDCLASS(VisualShaderNodeSwitch, VisualShaderNode); public: + enum OpType { + OP_TYPE_FLOAT, + OP_TYPE_INT, + OP_TYPE_VECTOR, + OP_TYPE_BOOLEAN, + OP_TYPE_TRANSFORM, + OP_TYPE_MAX, + }; + +protected: + OpType op_type = OP_TYPE_FLOAT; + + static void _bind_methods(); + +public: virtual String get_caption() const override; virtual int get_input_port_count() const override; @@ -2014,22 +2018,17 @@ public: virtual PortType get_output_port_type(int p_port) const override; virtual String get_output_port_name(int p_port) const override; + void set_op_type(OpType p_type); + OpType get_op_type() const; + + virtual Vector<StringName> get_editable_properties() 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; VisualShaderNodeSwitch(); }; -class VisualShaderNodeScalarSwitch : public VisualShaderNodeSwitch { - GDCLASS(VisualShaderNodeScalarSwitch, VisualShaderNodeSwitch); - -public: - virtual String get_caption() const override; - - virtual PortType get_input_port_type(int p_port) const override; - virtual PortType get_output_port_type(int p_port) const override; - - VisualShaderNodeScalarSwitch(); -}; +VARIANT_ENUM_CAST(VisualShaderNodeSwitch::OpType) /////////////////////////////////////// /// FRESNEL diff --git a/scene/resources/visual_shader_sdf_nodes.cpp b/scene/resources/visual_shader_sdf_nodes.cpp new file mode 100644 index 0000000000..d25e32b070 --- /dev/null +++ b/scene/resources/visual_shader_sdf_nodes.cpp @@ -0,0 +1,283 @@ +/*************************************************************************/ +/* visual_shader_sdf_nodes.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "visual_shader_sdf_nodes.h" + +// VisualShaderNodeSDFToScreenUV + +String VisualShaderNodeSDFToScreenUV::get_caption() const { + return "SDFToScreenUV"; +} + +int VisualShaderNodeSDFToScreenUV::get_input_port_count() const { + return 1; +} + +VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSDFToScreenUV::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeSDFToScreenUV::get_output_port_count() const { + return 1; +} + +VisualShaderNodeSDFToScreenUV::PortType VisualShaderNodeSDFToScreenUV::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeSDFToScreenUV::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeSDFToScreenUV::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 "\t" + p_output_vars[0] + " = vec3(sdf_to_screen_uv(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeSDFToScreenUV::VisualShaderNodeSDFToScreenUV() { +} + +// VisualShaderNodeScreenUVToSDF + +String VisualShaderNodeScreenUVToSDF::get_caption() const { + return "ScreenUVToSDF"; +} + +int VisualShaderNodeScreenUVToSDF::get_input_port_count() const { + return 1; +} + +VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeScreenUVToSDF::get_input_port_name(int p_port) const { + return "uv"; +} + +int VisualShaderNodeScreenUVToSDF::get_output_port_count() const { + return 1; +} + +VisualShaderNodeScreenUVToSDF::PortType VisualShaderNodeScreenUVToSDF::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeScreenUVToSDF::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeScreenUVToSDF::get_input_port_default_hint(int p_port) const { + if (p_port == 0) { + return "default"; + } + return ""; +} + +String VisualShaderNodeScreenUVToSDF::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 "\t" + p_output_vars[0] + " = vec3(screen_uv_to_sdf(" + (p_input_vars[0] == String() ? "SCREEN_UV" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeScreenUVToSDF::VisualShaderNodeScreenUVToSDF() { +} + +// VisualShaderNodeTextureSDF + +String VisualShaderNodeTextureSDF::get_caption() const { + return "TextureSDF"; +} + +int VisualShaderNodeTextureSDF::get_input_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDF::PortType VisualShaderNodeTextureSDF::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDF::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeTextureSDF::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDF::PortType VisualShaderNodeTextureSDF::get_output_port_type(int p_port) const { + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeTextureSDF::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTextureSDF::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 "\t" + p_output_vars[0] + " = texture_sdf(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + ");\n"; +} + +VisualShaderNodeTextureSDF::VisualShaderNodeTextureSDF() { +} + +// VisualShaderNodeTextureSDFNormal + +String VisualShaderNodeTextureSDFNormal::get_caption() const { + return "TextureSDFNormal"; +} + +int VisualShaderNodeTextureSDFNormal::get_input_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_input_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDFNormal::get_input_port_name(int p_port) const { + return "sdf_pos"; +} + +int VisualShaderNodeTextureSDFNormal::get_output_port_count() const { + return 1; +} + +VisualShaderNodeTextureSDFNormal::PortType VisualShaderNodeTextureSDFNormal::get_output_port_type(int p_port) const { + return PORT_TYPE_VECTOR; +} + +String VisualShaderNodeTextureSDFNormal::get_output_port_name(int p_port) const { + return ""; +} + +String VisualShaderNodeTextureSDFNormal::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 "\t" + p_output_vars[0] + " = vec3(texture_sdf_normal(" + (p_input_vars[0] == String() ? "vec2(0.0)" : p_input_vars[0] + ".xy") + "), 0.0f);\n"; +} + +VisualShaderNodeTextureSDFNormal::VisualShaderNodeTextureSDFNormal() { +} + +// VisualShaderNodeSDFRaymarch + +String VisualShaderNodeSDFRaymarch::get_caption() const { + return "SDFRaymarch"; +} + +int VisualShaderNodeSDFRaymarch::get_input_port_count() const { + return 2; +} + +VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_input_port_type(int p_port) const { + if (p_port == 0 || p_port == 1) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeSDFRaymarch::get_input_port_name(int p_port) const { + if (p_port == 0) { + return "from_pos"; + } else if (p_port == 1) { + return "to_pos"; + } + return String(); +} + +int VisualShaderNodeSDFRaymarch::get_output_port_count() const { + return 3; +} + +VisualShaderNodeSDFRaymarch::PortType VisualShaderNodeSDFRaymarch::get_output_port_type(int p_port) const { + if (p_port == 0) { + return PORT_TYPE_SCALAR; + } else if (p_port == 1) { + return PORT_TYPE_BOOLEAN; + } else if (p_port == 2) { + return PORT_TYPE_VECTOR; + } + return PORT_TYPE_SCALAR; +} + +String VisualShaderNodeSDFRaymarch::get_output_port_name(int p_port) const { + if (p_port == 0) { + return "distance"; + } else if (p_port == 1) { + return "hit"; + } else if (p_port == 2) { + return "end_pos"; + } + return String(); +} + +String VisualShaderNodeSDFRaymarch::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { + String code; + + code += "\t{\n"; + + if (p_input_vars[0] == String()) { + code += "\t\tvec2 __from_pos = vec2(0.0f);\n"; + } else { + code += "\t\tvec2 __from_pos = " + p_input_vars[0] + ".xy;\n"; + } + + if (p_input_vars[1] == String()) { + code += "\t\tvec2 __to_pos = vec2(0.0f);\n"; + } else { + code += "\t\tvec2 __to_pos = " + p_input_vars[1] + ".xy;\n"; + } + + code += "\n\t\tvec2 __at = __from_pos;\n"; + code += "\t\tfloat __max_dist = distance(__from_pos, __to_pos);\n"; + code += "\t\tvec2 __dir = normalize(__to_pos - __from_pos);\n\n"; + + code += "\t\tfloat __accum = 0.0f;\n"; + code += "\t\twhile(__accum < __max_dist) {\n"; + code += "\t\t\tfloat __d = texture_sdf(__at);\n"; + code += "\t\t\t__accum += __d;\n"; + code += "\t\t\tif (__d < 0.01f) {\n"; + code += "\t\t\t\tbreak;\n"; + code += "\t\t\t}\n"; + code += "\t\t\t__at += __d * __dir;\n"; + code += "\t\t}\n"; + + code += "\t\tfloat __dist = min(__max_dist, __accum);\n"; + code += "\t\t" + p_output_vars[0] + " = __dist;\n"; + code += "\t\t" + p_output_vars[1] + " = __accum < __max_dist;\n"; + code += "\t\t" + p_output_vars[2] + " = vec3(__from_pos + __dir * __dist, 0.0f);\n"; + + code += "\t}\n"; + + return code; +} + +VisualShaderNodeSDFRaymarch::VisualShaderNodeSDFRaymarch() { + simple_decl = false; +} diff --git a/scene/resources/visual_shader_sdf_nodes.h b/scene/resources/visual_shader_sdf_nodes.h new file mode 100644 index 0000000000..0fcf5ec0b5 --- /dev/null +++ b/scene/resources/visual_shader_sdf_nodes.h @@ -0,0 +1,132 @@ +/*************************************************************************/ +/* visual_shader_sdf_nodes.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 VISUAL_SHADER_SDF_NODES_H +#define VISUAL_SHADER_SDF_NODES_H + +#include "scene/resources/visual_shader.h" + +class VisualShaderNodeSDFToScreenUV : public VisualShaderNode { + GDCLASS(VisualShaderNodeSDFToScreenUV, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeSDFToScreenUV(); +}; + +class VisualShaderNodeScreenUVToSDF : public VisualShaderNode { + GDCLASS(VisualShaderNodeScreenUVToSDF, VisualShaderNode); + +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_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; + + VisualShaderNodeScreenUVToSDF(); +}; + +class VisualShaderNodeTextureSDF : public VisualShaderNode { + GDCLASS(VisualShaderNodeTextureSDF, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeTextureSDF(); +}; + +class VisualShaderNodeTextureSDFNormal : public VisualShaderNode { + GDCLASS(VisualShaderNodeTextureSDFNormal, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeTextureSDFNormal(); +}; + +class VisualShaderNodeSDFRaymarch : public VisualShaderNode { + GDCLASS(VisualShaderNodeSDFRaymarch, VisualShaderNode); + +public: + virtual String get_caption() const override; + + virtual int get_input_port_count() const override; + virtual PortType get_input_port_type(int p_port) const override; + virtual String get_input_port_name(int p_port) const override; + + virtual int get_output_port_count() const override; + virtual PortType get_output_port_type(int p_port) const override; + virtual String get_output_port_name(int p_port) const override; + + virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override; + + VisualShaderNodeSDFRaymarch(); +}; + +#endif // VISUAL_SHADER_SDF_NODES_H diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index 41d3fe20be..ccdc5bebd0 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -34,12 +34,13 @@ #include "scene/2d/camera_2d.h" #include "scene/2d/visibility_notifier_2d.h" #include "scene/main/window.h" +#include "servers/navigation_server_2d.h" #include "servers/physics_server_2d.h" #include "servers/rendering_server.h" struct SpatialIndexer2D { struct CellRef { - int ref; + int ref = 0; _FORCE_INLINE_ int inc() { ref++; @@ -49,10 +50,6 @@ struct SpatialIndexer2D { ref--; return ref; } - - _FORCE_INLINE_ CellRef() { - ref = 0; - } }; struct CellKey { @@ -61,7 +58,7 @@ struct SpatialIndexer2D { int32_t x; int32_t y; }; - uint64_t key; + uint64_t key = 0; }; bool operator==(const CellKey &p_key) const { return key == p_key.key; } @@ -86,9 +83,9 @@ struct SpatialIndexer2D { Map<Viewport *, ViewportData> viewports; - bool changed; + bool changed = false; - uint64_t pass; + uint64_t pass = 0; void _notifier_update_cells(VisibilityNotifier2D *p_notifier, const Rect2 &p_rect, bool p_add) { Point2i begin = p_rect.position; @@ -111,7 +108,7 @@ struct SpatialIndexer2D { ERR_CONTINUE(!E); if (E->get().notifiers[p_notifier].dec() == 0) { E->get().notifiers.erase(p_notifier); - if (E->get().notifiers.empty()) { + if (E->get().notifiers.is_empty()) { cells.erase(E); } } @@ -156,7 +153,7 @@ struct SpatialIndexer2D { } } - while (!removed.empty()) { + while (!removed.is_empty()) { p_notifier->_exit_viewport(removed.front()->get()); removed.pop_front(); } @@ -189,7 +186,7 @@ struct SpatialIndexer2D { removed.push_back(E->key()); } - while (!removed.empty()) { + while (!removed.is_empty()) { removed.front()->get()->_exit_viewport(p_viewport); removed.pop_front(); } @@ -271,12 +268,12 @@ struct SpatialIndexer2D { } } - while (!added.empty()) { + while (!added.is_empty()) { added.front()->get()->_enter_viewport(E->key()); added.pop_front(); } - while (!removed.empty()) { + while (!removed.is_empty()) { E->get().notifiers.erase(removed.front()->get()); removed.front()->get()->_exit_viewport(E->key()); removed.pop_front(); @@ -287,8 +284,6 @@ struct SpatialIndexer2D { } SpatialIndexer2D() { - pass = 0; - changed = false; cell_size = GLOBAL_DEF("world/2d/cell_size", 100); } }; @@ -321,14 +316,18 @@ void World2D::_update() { indexer->_update(); } -RID World2D::get_canvas() { +RID World2D::get_canvas() const { return canvas; } -RID World2D::get_space() { +RID World2D::get_space() const { return space; } +RID World2D::get_navigation_map() const { + return navigation_map; +} + void World2D::get_viewport_list(List<Viewport *> *r_viewports) { for (Map<Viewport *, SpatialIndexer2D::ViewportData>::Element *E = indexer->viewports.front(); E; E = E->next()) { r_viewports->push_back(E->key()); @@ -338,11 +337,13 @@ void World2D::get_viewport_list(List<Viewport *> *r_viewports) { void World2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_canvas"), &World2D::get_canvas); ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &World2D::get_navigation_map); 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, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState2D", 0), "", "get_direct_space_state"); } @@ -352,9 +353,9 @@ PhysicsDirectSpaceState2D *World2D::get_direct_space_state() { World2D::World2D() { canvas = RenderingServer::get_singleton()->canvas_create(); - space = PhysicsServer2D::get_singleton()->space_create(); - //set space2D to be more friendly with pixels than meters, by adjusting some constants + // Create and configure space2D to be more friendly with pixels than meters + space = PhysicsServer2D::get_singleton()->space_create(); PhysicsServer2D::get_singleton()->space_set_active(space, true); PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY, GLOBAL_DEF("physics/2d/default_gravity", 98)); PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR, GLOBAL_DEF("physics/2d/default_gravity_vector", Vector2(0, 1))); @@ -362,11 +363,19 @@ World2D::World2D() { ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_linear_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_linear_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); PhysicsServer2D::get_singleton()->area_set_param(space, PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/2d/default_angular_damp", 1.0)); ProjectSettings::get_singleton()->set_custom_property_info("physics/2d/default_angular_damp", PropertyInfo(Variant::FLOAT, "physics/2d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); + + // Create and configure the navigation_map to be more friendly with pixels than meters. + navigation_map = NavigationServer2D::get_singleton()->map_create(); + NavigationServer2D::get_singleton()->map_set_active(navigation_map, true); + NavigationServer2D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/2d/default_cell_size", 10)); + NavigationServer2D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/2d/default_edge_connection_margin", 5)); + indexer = memnew(SpatialIndexer2D); } World2D::~World2D() { RenderingServer::get_singleton()->free(canvas); PhysicsServer2D::get_singleton()->free(space); + NavigationServer2D::get_singleton()->free(navigation_map); memdelete(indexer); } diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h index 11614f9aa4..38abf3d7ad 100644 --- a/scene/resources/world_2d.h +++ b/scene/resources/world_2d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -44,6 +44,7 @@ class World2D : public Resource { RID canvas; RID space; + RID navigation_map; SpatialIndexer2D *indexer; @@ -63,8 +64,9 @@ protected: void _update(); public: - RID get_canvas(); - RID get_space(); + RID get_canvas() const; + RID get_space() const; + RID get_navigation_map() const; PhysicsDirectSpaceState2D *get_direct_space_state(); diff --git a/scene/resources/world_3d.cpp b/scene/resources/world_3d.cpp index b8fb3825ce..0e9f7a6cf2 100644 --- a/scene/resources/world_3d.cpp +++ b/scene/resources/world_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -35,6 +35,7 @@ #include "scene/3d/camera_3d.h" #include "scene/3d/visibility_notifier_3d.h" #include "scene/scene_string_names.h" +#include "servers/navigation_server_3d.h" struct SpatialIndexer { Octree<VisibilityNotifier3D> octree; @@ -97,7 +98,7 @@ struct SpatialIndexer { } } - while (!removed.empty()) { + while (!removed.is_empty()) { p_notifier->_exit_camera(removed.front()->get()); removed.pop_front(); } @@ -125,7 +126,7 @@ struct SpatialIndexer { removed.push_back(E->key()); } - while (!removed.empty()) { + while (!removed.is_empty()) { removed.front()->get()->_exit_camera(p_camera); removed.pop_front(); } @@ -175,12 +176,12 @@ struct SpatialIndexer { } } - while (!added.empty()) { + while (!added.is_empty()) { added.front()->get()->_enter_camera(E->key()); added.pop_front(); } - while (!removed.empty()) { + while (!removed.is_empty()) { E->get().notifiers.erase(removed.front()->get()); removed.front()->get()->_exit_camera(E->key()); removed.pop_front(); @@ -243,6 +244,10 @@ RID World3D::get_space() const { return space; } +RID World3D::get_navigation_map() const { + return navigation_map; +} + RID World3D::get_scenario() const { return scenario; } @@ -310,6 +315,7 @@ void World3D::get_camera_list(List<Camera3D *> *r_cameras) { void World3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_space"), &World3D::get_space); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &World3D::get_navigation_map); ClassDB::bind_method(D_METHOD("get_scenario"), &World3D::get_scenario); ClassDB::bind_method(D_METHOD("set_environment", "env"), &World3D::set_environment); ClassDB::bind_method(D_METHOD("get_environment"), &World3D::get_environment); @@ -322,6 +328,7 @@ void World3D::_bind_methods() { 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, "navigation_map", PROPERTY_HINT_NONE, "", 0), "", "get_navigation_map"); 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"); } @@ -338,6 +345,11 @@ World3D::World3D() { PhysicsServer3D::get_singleton()->area_set_param(space, PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP, GLOBAL_DEF("physics/3d/default_angular_damp", 0.1)); ProjectSettings::get_singleton()->set_custom_property_info("physics/3d/default_angular_damp", PropertyInfo(Variant::FLOAT, "physics/3d/default_angular_damp", PROPERTY_HINT_RANGE, "-1,100,0.001,or_greater")); + navigation_map = NavigationServer3D::get_singleton()->map_create(); + NavigationServer3D::get_singleton()->map_set_active(navigation_map, true); + NavigationServer3D::get_singleton()->map_set_cell_size(navigation_map, GLOBAL_DEF("navigation/3d/default_cell_size", 0.3)); + NavigationServer3D::get_singleton()->map_set_edge_connection_margin(navigation_map, GLOBAL_DEF("navigation/3d/default_edge_connection_margin", 5.0)); // Five meters, depends a lot on the agent's radius + #ifdef _3D_DISABLED indexer = nullptr; #else @@ -348,6 +360,7 @@ World3D::World3D() { World3D::~World3D() { PhysicsServer3D::get_singleton()->free(space); RenderingServer::get_singleton()->free(scenario); + NavigationServer3D::get_singleton()->free(navigation_map); #ifndef _3D_DISABLED memdelete(indexer); diff --git a/scene/resources/world_3d.h b/scene/resources/world_3d.h index 93e9c72e59..4e2717a2bb 100644 --- a/scene/resources/world_3d.h +++ b/scene/resources/world_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -46,6 +46,7 @@ class World3D : public Resource { private: RID space; + RID navigation_map; RID scenario; SpatialIndexer *indexer; Ref<Environment> environment; @@ -70,6 +71,7 @@ protected: public: RID get_space() const; + RID get_navigation_map() const; RID get_scenario() const; void set_environment(const Ref<Environment> &p_environment); diff --git a/scene/resources/world_margin_shape_3d.cpp b/scene/resources/world_margin_shape_3d.cpp index 0936fcc657..28d50e1921 100644 --- a/scene/resources/world_margin_shape_3d.cpp +++ b/scene/resources/world_margin_shape_3d.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ @@ -69,7 +69,6 @@ void WorldMarginShape3D::set_plane(Plane p_plane) { plane = p_plane; _update_shape(); notify_change_to_owners(); - _change_notify("plane"); } Plane WorldMarginShape3D::get_plane() const { diff --git a/scene/resources/world_margin_shape_3d.h b/scene/resources/world_margin_shape_3d.h index 8099592d80..00417c4408 100644 --- a/scene/resources/world_margin_shape_3d.h +++ b/scene/resources/world_margin_shape_3d.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index a72066e7a8..892802c103 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index b4d2429d7f..655e49c6f9 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 */ |