diff options
Diffstat (limited to 'scene')
50 files changed, 487 insertions, 314 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 3d7ff5f1fd..7a50574be2 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -93,7 +93,7 @@ Rect2 AnimatedSprite::_get_rect() const { Point2 ofs = offset; if (centered) - ofs -= s / 2; + ofs -= Size2(s) / 2; if (s == Size2(0, 0)) s = Size2(1, 1); @@ -393,19 +393,30 @@ void AnimatedSprite::_notification(int p_what) { timeout = _get_frame_duration(); int fc = frames->get_frame_count(animation); - if (frame >= fc - 1) { + if ((!backwards && frame >= fc - 1) || (backwards && frame <= 0)) { if (frames->get_animation_loop(animation)) { - frame = 0; + if (backwards) + frame = fc - 1; + else + frame = 0; + emit_signal(SceneStringNames::get_singleton()->animation_finished); } else { - frame = fc - 1; + if (backwards) + frame = 0; + else + frame = fc - 1; + if (!is_over) { is_over = true; emit_signal(SceneStringNames::get_singleton()->animation_finished); } } } else { - frame++; + if (backwards) + frame--; + else + frame++; } update(); @@ -594,10 +605,12 @@ bool AnimatedSprite::_is_playing() const { return playing; } -void AnimatedSprite::play(const StringName &p_animation) { +void AnimatedSprite::play(const StringName &p_animation, const bool p_backwards) { if (p_animation) set_animation(p_animation); + + backwards = p_backwards; _set_playing(true); } @@ -666,7 +679,7 @@ void AnimatedSprite::_bind_methods() { ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite::_set_playing); ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite::_is_playing); - ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite::play, DEFVAL(StringName())); + ClassDB::bind_method(D_METHOD("play", "anim", "backwards"), &AnimatedSprite::play, DEFVAL(StringName())); ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite::stop); ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite::is_playing); @@ -713,6 +726,7 @@ AnimatedSprite::AnimatedSprite() { frame = 0; speed_scale = 1.0f; playing = false; + backwards = false; animation = "default"; timeout = 0; is_over = false; diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h index 8753f88799..2cc372bd93 100644 --- a/scene/2d/animated_sprite.h +++ b/scene/2d/animated_sprite.h @@ -128,6 +128,7 @@ class AnimatedSprite : public Node2D { Ref<SpriteFrames> frames; bool playing; + bool backwards; StringName animation; int frame; float speed_scale; @@ -169,7 +170,7 @@ public: void set_sprite_frames(const Ref<SpriteFrames> &p_frames); Ref<SpriteFrames> get_sprite_frames() const; - void play(const StringName &p_animation = StringName()); + void play(const StringName &p_animation = StringName(), const bool p_backwards = false); void stop(); bool is_playing() const; diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index d54070df8d..f43d97eb2a 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "collision_object_2d.h" + #include "scene/scene_string_names.h" #include "servers/physics_2d_server.h" @@ -56,7 +57,7 @@ void CollisionObject2D::_notification(int p_what) { _update_pickable(); //get space - } + } break; case NOTIFICATION_ENTER_CANVAS: { @@ -64,7 +65,7 @@ void CollisionObject2D::_notification(int p_what) { Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); else Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, get_canvas_layer_instance_id()); - } + } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -101,7 +102,7 @@ void CollisionObject2D::_notification(int p_what) { Physics2DServer::get_singleton()->area_attach_canvas_instance_id(rid, 0); else Physics2DServer::get_singleton()->body_attach_canvas_instance_id(rid, 0); - } + } break; } } diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index c50a8d4a1a..721b52edaa 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -37,20 +37,8 @@ void CPUParticles2D::set_emitting(bool p_emitting) { emitting = p_emitting; - if (!is_processing_internal()) { + if (emitting) set_process_internal(true); - if (is_inside_tree()) { -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } - } } void CPUParticles2D::set_amount(int p_amount) { @@ -365,7 +353,8 @@ void CPUParticles2D::set_param_curve(Parameter p_param, const Ref<Curve> &p_curv } break; case PARAM_ANIM_OFFSET: { } break; - default: {} + default: { + } } } Ref<Curve> CPUParticles2D::get_param_curve(Parameter p_param) const { @@ -586,7 +575,7 @@ void CPUParticles2D::_particles_process(float p_delta) { if (restart_time >= prev_time && restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } @@ -594,13 +583,13 @@ void CPUParticles2D::_particles_process(float p_delta) { if (restart_time >= prev_time) { restart = true; if (fractional_delta) { - local_delta = (lifetime - restart_time + time) * lifetime; + local_delta = lifetime - restart_time + time; } } else if (restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } } @@ -941,6 +930,26 @@ void CPUParticles2D::_update_particle_data_buffer() { #endif } +void CPUParticles2D::_set_redraw(bool p_redraw) { + if (redraw == p_redraw) + return; + redraw = p_redraw; +#ifndef NO_THREADS + update_mutex->lock(); +#endif + if (redraw) { + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); + } else { + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); + } +#ifndef NO_THREADS + update_mutex->unlock(); +#endif + update(); // redraw to update render list +} + void CPUParticles2D::_update_render_thread() { #ifndef NO_THREADS @@ -957,38 +966,19 @@ void CPUParticles2D::_update_render_thread() { void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + set_process_internal(emitting); } if (p_what == NOTIFICATION_EXIT_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + _set_redraw(false); } if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { } if (p_what == NOTIFICATION_DRAW) { + if (!redraw) + return; // dont add to render list RID texrid; if (texture.is_valid()) { @@ -1005,26 +995,20 @@ void CPUParticles2D::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (particles.size() == 0 || !is_visible_in_tree()) + if (particles.size() == 0 || !is_visible_in_tree()) { + _set_redraw(false); return; + } float delta = get_process_delta_time(); if (emitting) { - inactive_time = 0; } else { inactive_time += delta; if (inactive_time > lifetime * 1.2) { set_process_internal(false); -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->canvas_item_set_update_when_visible(get_canvas_item(), false); + _set_redraw(false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif //reset variables time = 0; inactive_time = 0; @@ -1033,6 +1017,7 @@ void CPUParticles2D::_notification(int p_what) { return; } } + _set_redraw(true); if (time == 0 && pre_process_time > 0.0) { @@ -1354,6 +1339,7 @@ CPUParticles2D::CPUParticles2D() { inactive_time = 0; frame_remainder = 0; cycle = 0; + redraw = false; mesh = VisualServer::get_singleton()->mesh_create(); multimesh = VisualServer::get_singleton()->multimesh_create(); diff --git a/scene/2d/cpu_particles_2d.h b/scene/2d/cpu_particles_2d.h index b1adf62980..23d2586331 100644 --- a/scene/2d/cpu_particles_2d.h +++ b/scene/2d/cpu_particles_2d.h @@ -103,6 +103,7 @@ private: float inactive_time; float frame_remainder; int cycle; + bool redraw; RID mesh; RID multimesh; @@ -179,6 +180,8 @@ private: void _update_mesh_texture(); + void _set_redraw(bool p_redraw); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp index 105eb82afb..73692e0535 100644 --- a/scene/2d/line_2d.cpp +++ b/scene/2d/line_2d.cpp @@ -112,6 +112,14 @@ int Line2D::get_point_count() const { return _points.size(); } +void Line2D::clear_points() { + int count = _points.size(); + if (count > 0) { + _points.resize(0); + update(); + } +} + void Line2D::add_point(Vector2 pos) { _points.append(pos); update(); @@ -313,6 +321,8 @@ void Line2D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_point", "position"), &Line2D::add_point); ClassDB::bind_method(D_METHOD("remove_point", "i"), &Line2D::remove_point); + ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points); + ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width); ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width); diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h index 5bbd38e460..32befab2d3 100644 --- a/scene/2d/line_2d.h +++ b/scene/2d/line_2d.h @@ -70,6 +70,8 @@ public: int get_point_count() const; + void clear_points(); + void add_point(Vector2 pos); void remove_point(int i); diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 96e13396c5..4ead1bbd1e 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -207,7 +207,7 @@ void ParallaxBackground::_bind_methods() { ParallaxBackground::ParallaxBackground() { scale = 1.0; - set_layer(-1); //behind all by default + set_layer(-100); //behind all by default base_scale = Vector2(1, 1); ignore_camera_zoom = false; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 1b7e1a6b8b..690f1d4b4a 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -199,7 +199,7 @@ real_t StaticBody2D::get_constant_angular_velocity() const { #ifndef DISABLE_DEPRECATED void StaticBody2D::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } @@ -229,7 +229,7 @@ real_t StaticBody2D::get_friction() const { void StaticBody2D::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } @@ -626,7 +626,7 @@ real_t RigidBody2D::get_weight() const { #ifndef DISABLE_DEPRECATED void RigidBody2D::set_friction(real_t p_friction) { - if (p_friction == 1.0) { // default value, don't create an override for that + if (p_friction == 1.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } @@ -655,7 +655,7 @@ real_t RigidBody2D::get_friction() const { void RigidBody2D::set_bounce(real_t p_bounce) { - if (p_bounce == 0.0) { // default value, don't create an override for that + if (p_bounce == 0.0 && physics_material_override.is_null()) { // default value, don't create an override for that return; } diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index ba103a8bf0..a8c7622828 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -363,7 +363,7 @@ Rect2 Sprite::get_rect() const { Point2 ofs = offset; if (centered) - ofs -= s / 2; + ofs -= Size2(s) / 2; if (s == Size2(0, 0)) s = Size2(1, 1); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index ed0a9c4915..3562011bc2 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -773,6 +773,7 @@ void TileMap::set_cell(int p_x, int p_y, int p_tile, bool p_flip_x, bool p_flip_ else _make_quadrant_dirty(Q); + used_size_cache_dirty = true; return; } @@ -1391,15 +1392,17 @@ Vector2 TileMap::_map_to_world(int p_x, int p_y, bool p_ignore_ofs) const { if (!p_ignore_ofs) { switch (half_offset) { - case HALF_OFFSET_X: { + case HALF_OFFSET_X: + case HALF_OFFSET_NEGATIVE_X: { if (ABS(p_y) & 1) { - ret += get_cell_transform()[0] * 0.5; + ret += get_cell_transform()[0] * (half_offset == HALF_OFFSET_X ? 0.5 : -0.5); } } break; - case HALF_OFFSET_Y: { + case HALF_OFFSET_Y: + case HALF_OFFSET_NEGATIVE_Y: { if (ABS(p_x) & 1) { - ret += get_cell_transform()[1] * 0.5; + ret += get_cell_transform()[1] * (half_offset == HALF_OFFSET_Y ? 0.5 : -0.5); } } break; default: {} @@ -1462,11 +1465,21 @@ Vector2 TileMap::world_to_map(const Vector2 &p_pos) const { ret.x -= 0.5; } } break; + case HALF_OFFSET_NEGATIVE_X: { + if (ret.y > 0 ? int(ret.y) & 1 : (int(ret.y) - 1) & 1) { + ret.x += 0.5; + } + } break; case HALF_OFFSET_Y: { if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { ret.y -= 0.5; } } break; + case HALF_OFFSET_NEGATIVE_Y: { + if (ret.x > 0 ? int(ret.x) & 1 : (int(ret.x) - 1) & 1) { + ret.y += 0.5; + } + } break; default: {} } @@ -1677,7 +1690,7 @@ void TileMap::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "cell_size", PROPERTY_HINT_RANGE, "1,8192,1"), "set_cell_size", "get_cell_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_quadrant_size", "get_quadrant_size"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "cell_custom_transform"), "set_custom_transform", "get_custom_transform"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled"), "set_half_offset", "get_half_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_half_offset", PROPERTY_HINT_ENUM, "Offset X,Offset Y,Disabled,Offset Negative X,Offset Negative Y"), "set_half_offset", "get_half_offset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_tile_origin", PROPERTY_HINT_ENUM, "Top Left,Center,Bottom Left"), "set_tile_origin", "get_tile_origin"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_y_sort"), "set_y_sort_mode", "is_y_sort_mode_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cell_clip_uv"), "set_clip_uv", "get_clip_uv"); @@ -1703,6 +1716,8 @@ void TileMap::_bind_methods() { BIND_ENUM_CONSTANT(HALF_OFFSET_X); BIND_ENUM_CONSTANT(HALF_OFFSET_Y); BIND_ENUM_CONSTANT(HALF_OFFSET_DISABLED); + BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_X); + BIND_ENUM_CONSTANT(HALF_OFFSET_NEGATIVE_Y); BIND_ENUM_CONSTANT(TILE_ORIGIN_TOP_LEFT); BIND_ENUM_CONSTANT(TILE_ORIGIN_CENTER); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index e450e1e256..6a1467aa48 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -52,6 +52,8 @@ public: HALF_OFFSET_X, HALF_OFFSET_Y, HALF_OFFSET_DISABLED, + HALF_OFFSET_NEGATIVE_X, + HALF_OFFSET_NEGATIVE_Y, }; enum TileOrigin { diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index e58e26d2d1..13d9181082 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -756,7 +756,6 @@ Area::Area() : monitorable = false; collision_mask = 1; collision_layer = 1; - set_ray_pickable(false); set_monitoring(true); set_monitorable(true); diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index d8c2042c88..f542b021be 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -52,7 +52,7 @@ void CollisionObject::_notification(int p_what) { _update_pickable(); //get space - }; + } break; case NOTIFICATION_TRANSFORM_CHANGED: { diff --git a/scene/3d/cpu_particles.cpp b/scene/3d/cpu_particles.cpp index 11dfbdb1f9..469a1e87db 100644 --- a/scene/3d/cpu_particles.cpp +++ b/scene/3d/cpu_particles.cpp @@ -47,20 +47,8 @@ PoolVector<Face3> CPUParticles::get_faces(uint32_t p_usage_flags) const { void CPUParticles::set_emitting(bool p_emitting) { emitting = p_emitting; - if (!is_processing_internal()) { + if (emitting) set_process_internal(true); - if (is_inside_tree()) { -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); - -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } - } } void CPUParticles::set_amount(int p_amount) { @@ -343,7 +331,8 @@ void CPUParticles::set_param_curve(Parameter p_param, const Ref<Curve> &p_curve) } break; case PARAM_ANIM_OFFSET: { } break; - default: {} + default: { + } } } Ref<Curve> CPUParticles::get_param_curve(Parameter p_param) const { @@ -556,7 +545,7 @@ void CPUParticles::_particles_process(float p_delta) { if (restart_time >= prev_time && restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } @@ -564,13 +553,13 @@ void CPUParticles::_particles_process(float p_delta) { if (restart_time >= prev_time) { restart = true; if (fractional_delta) { - local_delta = (1.0 - restart_time + time) * lifetime; + local_delta = lifetime - restart_time + time; } } else if (restart_time < time) { restart = true; if (fractional_delta) { - local_delta = (time - restart_time) * lifetime; + local_delta = time - restart_time; } } } @@ -1004,6 +993,27 @@ void CPUParticles::_update_particle_data_buffer() { #endif } +void CPUParticles::_set_redraw(bool p_redraw) { + if (redraw == p_redraw) + return; + redraw = p_redraw; +#ifndef NO_THREADS + update_mutex->lock(); +#endif + if (redraw) { + VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); + VS::get_singleton()->multimesh_set_visible_instances(multimesh, -1); + } else { + VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); + VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); + VS::get_singleton()->multimesh_set_visible_instances(multimesh, 0); + } +#ifndef NO_THREADS + update_mutex->unlock(); +#endif +} + void CPUParticles::_update_render_thread() { #ifndef NO_THREADS @@ -1022,31 +1032,11 @@ void CPUParticles::_update_render_thread() { void CPUParticles::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->connect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, true); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + set_process_internal(emitting); } if (p_what == NOTIFICATION_EXIT_TREE) { - if (is_processing_internal()) { - -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif - } + _set_redraw(false); } if (p_what == NOTIFICATION_PAUSED || p_what == NOTIFICATION_UNPAUSED) { @@ -1054,26 +1044,20 @@ void CPUParticles::_notification(int p_what) { if (p_what == NOTIFICATION_INTERNAL_PROCESS) { - if (particles.size() == 0 || !is_visible_in_tree()) + if (particles.size() == 0 || !is_visible_in_tree()) { + _set_redraw(false); return; + } float delta = get_process_delta_time(); if (emitting) { - inactive_time = 0; } else { inactive_time += delta; if (inactive_time > lifetime * 1.2) { set_process_internal(false); -#ifndef NO_THREADS - update_mutex->lock(); -#endif - VS::get_singleton()->disconnect("frame_pre_draw", this, "_update_render_thread"); - VS::get_singleton()->instance_geometry_set_flag(get_instance(), VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, false); + _set_redraw(false); -#ifndef NO_THREADS - update_mutex->unlock(); -#endif //reset variables time = 0; inactive_time = 0; @@ -1082,6 +1066,7 @@ void CPUParticles::_notification(int p_what) { return; } } + _set_redraw(true); bool processed = false; @@ -1406,6 +1391,7 @@ CPUParticles::CPUParticles() { inactive_time = 0; frame_remainder = 0; cycle = 0; + redraw = false; multimesh = VisualServer::get_singleton()->multimesh_create(); set_base(multimesh); diff --git a/scene/3d/cpu_particles.h b/scene/3d/cpu_particles.h index b50befe7be..b863a3cb3f 100644 --- a/scene/3d/cpu_particles.h +++ b/scene/3d/cpu_particles.h @@ -104,6 +104,7 @@ private: float inactive_time; float frame_remainder; int cycle; + bool redraw; RID multimesh; @@ -178,6 +179,8 @@ private: void _update_render_thread(); + void _set_redraw(bool p_redraw); + protected: static void _bind_methods(); void _notification(int p_what); diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 848889155b..89072519d5 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -96,7 +96,7 @@ void MeshInstance::_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::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.01")); + p_list->push_back(PropertyInfo(Variant::REAL, E->get(), PROPERTY_HINT_RANGE, "0,1,0.00001")); } if (mesh.is_valid()) { diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index d6544c39da..83f99a2e3c 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -178,7 +178,7 @@ void Spatial::_notification(int p_what) { get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world, NULL, 0); } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() && get_tree()->is_node_being_edited(this)) { //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); get_tree()->call_group_flags(0, SceneStringNames::get_singleton()->_spatial_editor_group, SceneStringNames::get_singleton()->_request_gizmo, this); diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index 5df3da93e1..68ad71d01c 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -440,13 +440,13 @@ float AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *sm, bool goto_next = false; - if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_IMMEDIATE) { - goto_next = fading_from == StringName(); - } else { + if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { goto_next = next_xfade >= (len_current - pos_current) || loops_current > 0; if (loops_current > 0) { next_xfade = 0; } + } else { + goto_next = fading_from == StringName(); } if (goto_next) { //loops should be used because fade time may be too small or zero and animation may have looped diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 0b6fa26bfc..fe1b8247ff 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -883,16 +883,16 @@ void AnimationTree::_process_graph(float p_delta) { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); - if (t->process_pass != process_pass) { + if (track->root_motion) { - t->process_pass = process_pass; - t->loc = Vector3(); - t->rot = Quat(); - t->rot_blend_accum = 0; - t->scale = Vector3(); - } + if (t->process_pass != process_pass) { - if (track->root_motion) { + t->process_pass = process_pass; + t->loc = Vector3(); + t->rot = Quat(); + t->rot_blend_accum = 0; + t->scale = Vector3(); + } float prev_time = time - delta; if (prev_time < 0) { @@ -946,6 +946,15 @@ void AnimationTree::_process_graph(float p_delta) { Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); //ERR_CONTINUE(err!=OK); //used for testing, should be removed + if (t->process_pass != process_pass) { + + t->process_pass = process_pass; + t->loc = loc; + t->rot = rot; + t->rot_blend_accum = 0; + t->scale = Vector3(); + } + scale -= Vector3(1.0, 1.0, 1.0); //helps make it work properly with Add nodes if (err != OK) @@ -978,8 +987,7 @@ void AnimationTree::_process_graph(float p_delta) { continue; if (t->process_pass != process_pass) { - Variant::CallError ce; - t->value = Variant::construct(value.get_type(), NULL, 0, ce); //reset + t->value = value; t->process_pass = process_pass; } @@ -1036,7 +1044,7 @@ void AnimationTree::_process_graph(float p_delta) { float bezier = a->bezier_track_interpolate(i, time); if (t->process_pass != process_pass) { - t->value = 0; + t->value = bezier; t->process_pass = process_pass; } diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 6a5d7839f4..23998183b8 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -223,6 +223,7 @@ void Tween::_bind_methods() { ADD_SIGNAL(MethodInfo("tween_started", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); ADD_SIGNAL(MethodInfo("tween_step", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"), PropertyInfo(Variant::REAL, "elapsed"), PropertyInfo(Variant::OBJECT, "value"))); ADD_SIGNAL(MethodInfo("tween_completed", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"))); + ADD_SIGNAL(MethodInfo("tween_all_completed")); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "repeat"), "set_repeat", "is_repeat"); ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_tween_process_mode", "get_tween_process_mode"); @@ -628,8 +629,10 @@ void Tween::_tween_process(float p_delta) { } pending_update--; - if (all_finished) + if (all_finished) { set_active(false); + emit_signal("tween_all_completed"); + } } void Tween::set_tween_process_mode(TweenProcessMode p_mode) { diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index c734136895..65e9cccd05 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "button.h" + #include "core/translation.h" #include "servers/visual_server.h" @@ -102,6 +103,7 @@ void Button::_notification(int p_what) { break; } + FALLTHROUGH; } case DRAW_PRESSED: { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 86894ce070..c7cd2bb6d8 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1388,7 +1388,10 @@ void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bo } update(); - _change_notify("anchor"); + _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) { diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 68e734502b..30ad81bb2e 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -770,7 +770,9 @@ void GraphEdit::_top_layer_draw() { } if (box_selecting) - top_layer->draw_rect(box_selecting_rect, Color(0.7, 0.7, 1.0, 0.3)); + top_layer->draw_rect( + box_selecting_rect, + get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); } void GraphEdit::set_selected(Node *p_child) { diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp index 8c588109d6..e8692d56d2 100644 --- a/scene/gui/graph_node.cpp +++ b/scene/gui/graph_node.cpp @@ -164,7 +164,6 @@ void GraphNode::_resort() { vofs += size.y; } - _change_notify(); update(); connpos_dirty = true; } @@ -409,9 +408,12 @@ Size2 GraphNode::get_minimum_size() const { void GraphNode::set_title(const String &p_title) { + if (title == p_title) + return; title = p_title; - minimum_size_changed(); update(); + _change_notify("title"); + minimum_size_changed(); } String GraphNode::get_title() const { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index bf6833e512..0c5dc39273 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "line_edit.h" + #include "core/message_queue.h" #include "core/os/keyboard.h" #include "core/os/os.h" @@ -320,7 +321,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_left + FALLTHROUGH; } case KEY_LEFT: { @@ -367,7 +368,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_right + FALLTHROUGH; } case KEY_RIGHT: { @@ -474,7 +475,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_home + FALLTHROUGH; } case KEY_HOME: { @@ -487,7 +488,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { handled = false; break; } - // numlock disabled. fallthrough to key_end + FALLTHROUGH; } case KEY_END: { @@ -1223,6 +1224,7 @@ void LineEdit::append_at_cursor(String p_text) { void LineEdit::clear_internal() { + deselect(); _clear_undo_stack(); cached_width = 0; cursor_pos = 0; diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index 28b124d143..94c73b2e42 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -594,7 +594,7 @@ void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) { item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.ID = p_ID == -1 ? items.size() : p_ID; items.push_back(item); update(); minimum_size_changed(); @@ -632,7 +632,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel item.text = p_label; item.xl_text = tr(p_label); item.accel = p_accel; - item.ID = p_ID; + item.ID = p_ID == -1 ? items.size() : p_ID; item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 9bcf10d5e7..00d6ac3b94 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -900,21 +900,13 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item Control::CursorShape RichTextLabel::get_cursor_shape(const Point2 &p_pos) const { - if (!underline_meta || selection.click) + if (selection.click) return CURSOR_ARROW; if (main->first_invalid_line < main->lines.size()) return CURSOR_ARROW; //invalid - int line = 0; - Item *item = NULL; - - ((RichTextLabel *)(this))->_find_click(main, p_pos, &item, &line); - - if (item && ((RichTextLabel *)(this))->_find_meta(item, NULL)) - return CURSOR_POINTING_HAND; - - return CURSOR_ARROW; + return get_default_cursor_shape(); } void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { @@ -1144,8 +1136,8 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { emit_signal("meta_hover_started", meta); } } else if (meta_hovering) { - emit_signal("meta_hover_ended", current_meta); meta_hovering = NULL; + emit_signal("meta_hover_ended", current_meta); current_meta = false; } } diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 28292309b9..e50a71b0ff 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -368,8 +368,10 @@ void ScrollContainer::update_scrollbars() { Ref<StyleBox> sb = get_stylebox("bg"); size -= sb->get_minimum_size(); - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); + Size2 hmin; + Size2 vmin; + if (scroll_h) hmin = h_scroll->get_combined_minimum_size(); + if (scroll_v) vmin = v_scroll->get_combined_minimum_size(); Size2 min = child_max_size; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2bf2364873..9acf8d40c9 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2517,7 +2517,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_left + FALLTHROUGH; } case KEY_LEFT: { @@ -2580,7 +2580,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_right + FALLTHROUGH; } case KEY_RIGHT: { @@ -2641,7 +2641,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_up + FALLTHROUGH; } case KEY_UP: { @@ -2694,7 +2694,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_down + FALLTHROUGH; } case KEY_DOWN: { @@ -2817,11 +2817,10 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_home + FALLTHROUGH; } -#ifdef APPLE_STYLE_KEYS case KEY_HOME: { - +#ifdef APPLE_STYLE_KEYS if (k->get_shift()) _pre_shift_selection(); @@ -2831,11 +2830,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _post_shift_selection(); else if (k->get_command() || k->get_control()) deselect(); - - } break; #else - case KEY_HOME: { - if (k->get_shift()) _pre_shift_selection(); @@ -2876,19 +2871,17 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { deselect(); _cancel_completion(); completion_hint = ""; - - } break; #endif + } break; case KEY_KP_1: { if (k->get_unicode() != 0) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_end + FALLTHROUGH; } -#ifdef APPLE_STYLE_KEYS case KEY_END: { - +#ifdef APPLE_STYLE_KEYS if (k->get_shift()) _pre_shift_selection(); @@ -2898,11 +2891,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _post_shift_selection(); else if (k->get_command() || k->get_control()) deselect(); - - } break; #else - case KEY_END: { - if (k->get_shift()) _pre_shift_selection(); @@ -2929,15 +2918,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _cancel_completion(); completion_hint = ""; - - } break; #endif + } break; case KEY_KP_9: { if (k->get_unicode() != 0) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_pageup + FALLTHROUGH; } case KEY_PAGEUP: { @@ -2960,7 +2948,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { scancode_handled = false; break; } - // numlock disabled. fallthrough to key_pagedown + FALLTHROUGH; } case KEY_PAGEDOWN: { @@ -3139,21 +3127,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (scancode_handled) accept_event(); - /* - if (!scancode_handled && !k->get_command() && !k->get_alt()) { - - if (k->get_unicode()>=32) { - if (readonly) - break; - - accept_event(); - } else { - - break; - } - } -*/ if (k->get_scancode() == KEY_INSERT) { set_insert_mode(!insert_mode); accept_event(); @@ -3196,7 +3170,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { end_complex_operation(); } accept_event(); - } else { } } diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 95f1fbbee5..33f0a3f45d 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -683,6 +683,7 @@ protected: TextEdit *text_editor; public: + virtual ~SyntaxHighlighter() {} virtual void _update_cache() = 0; virtual Map<int, TextEdit::HighlighterInfo> _get_line_syntax_highlighting(int p_line) = 0; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 19bef9fdf5..795b25cce0 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -223,8 +223,7 @@ void TextureButton::_notification(int p_what) { } if (has_focus() && focused.is_valid()) { - Rect2 drect(Point2(), get_size()); - draw_texture_rect(focused, drect, false); + draw_texture_rect(focused, _position_rect, false); }; } break; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 236c4dbe63..679b752fa3 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -29,7 +29,6 @@ /*************************************************************************/ #include "tree.h" -#include <limits.h> #include "core/math/math_funcs.h" #include "core/os/input.h" @@ -43,6 +42,8 @@ #include "editor/editor_node.h" #endif +#include <limits.h> + void TreeItem::move_to_top() { if (!parent || parent->children == this) @@ -940,6 +941,7 @@ int Tree::compute_item_height(TreeItem *p_item) const { int check_icon_h = cache.checked->get_height(); if (height < check_icon_h) height = check_icon_h; + FALLTHROUGH; } case TreeItem::CELL_MODE_STRING: case TreeItem::CELL_MODE_CUSTOM: @@ -1416,12 +1418,15 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 TreeItem *c = p_item->children; + int prev_ofs = children_pos.y - cache.offset.y + p_draw_ofs.y; + while (c) { if (cache.draw_relationship_lines > 0 && (!hide_root || c->parent != root)) { int root_ofs = children_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); int parent_ofs = p_pos.x + ((p_item->disable_folding || hide_folding) ? cache.hseparation : cache.item_margin); Point2i root_pos = Point2i(root_ofs, children_pos.y + label_h / 2) - cache.offset + p_draw_ofs; + if (c->get_children() != NULL) root_pos -= Point2i(cache.arrow->get_width(), 0); @@ -1434,12 +1439,13 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2 if (root_pos.y + line_width >= 0) { VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width); - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width); + VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), Point2i(parent_pos.x, prev_ofs), cache.relationship_line_color, line_width); } if (htotal < 0) { return -1; } + prev_ofs = root_pos.y; } if (htotal >= 0) { diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 2b1991ebb0..8cab1b1280 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -153,6 +153,7 @@ void CanvasLayer::_notification(int p_what) { VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas); VisualServer::get_singleton()->viewport_set_canvas_stacking(viewport, canvas, layer, get_position_in_parent()); VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform); + _update_follow_viewport(); } break; case NOTIFICATION_EXIT_TREE: { @@ -160,6 +161,7 @@ void CanvasLayer::_notification(int p_what) { vp->_canvas_layer_remove(this); VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas); viewport = RID(); + _update_follow_viewport(false); } break; case NOTIFICATION_MOVED_IN_PARENT: { @@ -235,6 +237,41 @@ RID CanvasLayer::get_canvas() const { return canvas; } + +void CanvasLayer::set_follow_viewport(bool p_enable) { + if (follow_viewport == p_enable) { + return; + } + + follow_viewport = p_enable; + _update_follow_viewport(); +} + +bool CanvasLayer::is_following_viewport() const { + return follow_viewport; +} + +void CanvasLayer::set_follow_viewport_scale(float p_ratio) { + follow_viewport_scale = p_ratio; + _update_follow_viewport(); +} + +float CanvasLayer::get_follow_viewport_scale() const { + return follow_viewport_scale; +} + +void CanvasLayer::_update_follow_viewport(bool p_force_exit) { + + if (!is_inside_tree()) { + return; + } + if (p_force_exit || !follow_viewport) { + VS::get_singleton()->canvas_set_parent(canvas, RID(), 1.0); + } else { + VS::get_singleton()->canvas_set_parent(canvas, vp->get_world_2d()->get_canvas(), follow_viewport_scale); + } +} + void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer); @@ -255,18 +292,30 @@ void CanvasLayer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_scale", "scale"), &CanvasLayer::set_scale); ClassDB::bind_method(D_METHOD("get_scale"), &CanvasLayer::get_scale); + ClassDB::bind_method(D_METHOD("set_follow_viewport", "enable"), &CanvasLayer::set_follow_viewport); + ClassDB::bind_method(D_METHOD("is_following_viewport"), &CanvasLayer::is_following_viewport); + + ClassDB::bind_method(D_METHOD("set_follow_viewport_scale", "scale"), &CanvasLayer::set_follow_viewport_scale); + ClassDB::bind_method(D_METHOD("get_follow_viewport_scale"), &CanvasLayer::get_follow_viewport_scale); + ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &CanvasLayer::set_custom_viewport); ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport); ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas); + ADD_GROUP("Layer", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer"); + ADD_GROUP("Transform", ""); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1080,1080,0.1,or_lesser,or_greater", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform"); + ADD_GROUP("", ""); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport"); + ADD_GROUP("Follow Viewport", "follow_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport_enable"), "set_follow_viewport", "is_following_viewport"); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "follow_viewport_scale", PROPERTY_HINT_RANGE, "0.001,1000,0.001,or_greater,or_lesser"), "set_follow_viewport_scale", "get_follow_viewport_scale"); } CanvasLayer::CanvasLayer() { @@ -280,6 +329,8 @@ CanvasLayer::CanvasLayer() { custom_viewport = NULL; custom_viewport_id = 0; 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 5d67245102..fa2558556c 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -55,8 +55,12 @@ class CanvasLayer : public Node { int sort_index; + bool follow_viewport; + float follow_viewport_scale; + void _update_xform(); void _update_locrotscale(); + void _update_follow_viewport(bool p_force_exit = false); protected: void _notification(int p_what); @@ -91,6 +95,12 @@ public: void reset_sort_index(); int get_sort_index(); + void set_follow_viewport(bool p_enable); + bool is_following_viewport() const; + + void set_follow_viewport_scale(float p_ratio); + float get_follow_viewport_scale() const; + RID get_canvas() const; CanvasLayer(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 04d7107fa4..128168ca72 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1313,6 +1313,10 @@ Node *Node::_get_child_by_name(const StringName &p_name) const { Node *Node::get_node_or_null(const NodePath &p_path) const { + if (p_path.is_empty()) { + return NULL; + } + if (!data.inside_tree && p_path.is_absolute()) { ERR_EXPLAIN("Can't use get_node() with absolute paths from outside the active scene tree."); ERR_FAIL_V(NULL); @@ -2830,10 +2834,22 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_DRAG_BEGIN); BIND_CONSTANT(NOTIFICATION_DRAG_END); BIND_CONSTANT(NOTIFICATION_PATH_CHANGED); - BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); BIND_CONSTANT(NOTIFICATION_INTERNAL_PROCESS); BIND_CONSTANT(NOTIFICATION_INTERNAL_PHYSICS_PROCESS); + BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER); + BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN); + BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT); + BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_GO_BACK_REQUEST); + BIND_CONSTANT(NOTIFICATION_WM_UNFOCUS_REQUEST); + BIND_CONSTANT(NOTIFICATION_OS_MEMORY_WARNING); + BIND_CONSTANT(NOTIFICATION_TRANSLATION_CHANGED); + BIND_CONSTANT(NOTIFICATION_WM_ABOUT); + BIND_CONSTANT(NOTIFICATION_CRASH); + BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); + BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT); BIND_ENUM_CONSTANT(PAUSE_MODE_STOP); BIND_ENUM_CONSTANT(PAUSE_MODE_PROCESS); diff --git a/scene/main/node.h b/scene/main/node.h index e6189389cb..b490db37c5 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -216,6 +216,7 @@ protected: public: enum { + // you can make your own, but don't use the same numbers as other notifications in other nodes NOTIFICATION_ENTER_TREE = 10, NOTIFICATION_EXIT_TREE = 11, @@ -231,10 +232,23 @@ public: NOTIFICATION_DRAG_BEGIN = 21, NOTIFICATION_DRAG_END = 22, NOTIFICATION_PATH_CHANGED = 23, - NOTIFICATION_TRANSLATION_CHANGED = 24, + //NOTIFICATION_TRANSLATION_CHANGED = 24, moved below NOTIFICATION_INTERNAL_PROCESS = 25, NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26, NOTIFICATION_POST_ENTER_TREE = 27, + //keep these linked to node + NOTIFICATION_WM_MOUSE_ENTER = MainLoop::NOTIFICATION_WM_MOUSE_ENTER, + NOTIFICATION_WM_MOUSE_EXIT = MainLoop::NOTIFICATION_WM_MOUSE_EXIT, + NOTIFICATION_WM_FOCUS_IN = MainLoop::NOTIFICATION_WM_FOCUS_IN, + NOTIFICATION_WM_FOCUS_OUT = MainLoop::NOTIFICATION_WM_FOCUS_OUT, + NOTIFICATION_WM_QUIT_REQUEST = MainLoop::NOTIFICATION_WM_QUIT_REQUEST, + NOTIFICATION_WM_GO_BACK_REQUEST = MainLoop::NOTIFICATION_WM_GO_BACK_REQUEST, + NOTIFICATION_WM_UNFOCUS_REQUEST = MainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST, + NOTIFICATION_OS_MEMORY_WARNING = MainLoop::NOTIFICATION_OS_MEMORY_WARNING, + NOTIFICATION_TRANSLATION_CHANGED = MainLoop::NOTIFICATION_TRANSLATION_CHANGED, + NOTIFICATION_WM_ABOUT = MainLoop::NOTIFICATION_WM_ABOUT, + NOTIFICATION_CRASH = MainLoop::NOTIFICATION_CRASH, + NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE }; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 689f18a09d..81c38cec89 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -658,13 +658,15 @@ void SceneTree::_notification(int p_notification) { } break; case NOTIFICATION_TRANSLATION_CHANGED: { if (!Engine::get_singleton()->is_editor_hint()) { - get_root()->propagate_notification(Node::NOTIFICATION_TRANSLATION_CHANGED); + get_root()->propagate_notification(p_notification); } } break; case NOTIFICATION_WM_UNFOCUS_REQUEST: { notify_group_flags(GROUP_CALL_REALTIME | GROUP_CALL_MULTILEVEL, "input", NOTIFICATION_WM_UNFOCUS_REQUEST); + get_root()->propagate_notification(p_notification); + } break; case NOTIFICATION_WM_ABOUT: { diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index e15a64604d..e098b3d53c 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -287,7 +287,7 @@ protected: public: enum { - NOTIFICATION_TRANSFORM_CHANGED = 29 + NOTIFICATION_TRANSFORM_CHANGED = 2000 }; enum GroupCallFlags { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index d86c241ec6..2524af9cfb 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -232,16 +232,16 @@ void Viewport::update_worlds() { find_world()->_update(get_tree()->get_frame()); } -void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion) { +void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape) { Transform object_transform = p_object->get_global_transform(); Transform camera_transform = p_camera->get_global_transform(); ObjectID id = p_object->get_instance_id(); - if (p_discard_empty_motion) { - //avoid sending the event unnecessarily if nothing really changed in the context + //avoid sending the fake event unnecessarily if nothing really changed in the context + if (object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { Ref<InputEventMouseMotion> mm = p_input_event; - if (mm.is_valid() && object_transform == physics_last_object_transform && camera_transform == physics_last_camera_transform && physics_last_id == id) { + if (mm.is_valid() && mm->get_device() == InputEvent::DEVICE_ID_INTERNAL) { return; //discarded } } @@ -251,31 +251,6 @@ void Viewport::_collision_object_input_event(CollisionObject *p_object, Camera * physics_last_id = id; } -void Viewport::_test_new_mouseover(ObjectID new_collider) { -#ifndef _3D_DISABLED - if (new_collider != physics_object_over) { - - if (physics_object_over) { - - CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); - if (co) { - co->_mouse_exit(); - } - } - - if (new_collider) { - - CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider)); - if (co) { - co->_mouse_enter(); - } - } - - physics_object_over = new_collider; - } -#endif -} - void Viewport::_notification(int p_what) { switch (p_what) { @@ -422,22 +397,22 @@ void Viewport::_notification(int p_what) { PhysicsDirectSpaceState::RayResult result; Physics2DDirectSpaceState *ss2d = Physics2DServer::get_singleton()->space_get_direct_state(find_world_2d()->get_space()); - bool discard_empty_motion = false; - - { // if no motion event exists, create a new one. This is necessary because objects or camera may have moved. + 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_motion = false; + bool has_mouse_event = false; for (List<Ref<InputEvent> >::Element *E = physics_picking_events.front(); E; E = E->next()) { - Ref<InputEventMouseMotion> mm = E->get(); - if (mm.is_valid()) { - has_mouse_motion = true; + Ref<InputEventMouse> m = E->get(); + if (m.is_valid()) { + has_mouse_event = true; break; } } - if (!has_mouse_motion && physics_has_last_mousepos) { + 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); @@ -446,25 +421,24 @@ void Viewport::_notification(int p_what) { mm->set_metakey(physics_last_mouse_state.meta); mm->set_button_mask(physics_last_mouse_state.mouse_mask); physics_picking_events.push_back(mm); - discard_empty_motion = true; } } - bool motion_tested = false; - while (physics_picking_events.size()) { Ref<InputEvent> ev = physics_picking_events.front()->get(); physics_picking_events.pop_front(); Vector2 pos; + bool is_mouse = false; Ref<InputEventMouseMotion> mm = ev; if (mm.is_valid()) { pos = mm->get_position(); - motion_tested = true; + is_mouse = true; + physics_has_last_mousepos = true; physics_last_mousepos = pos; physics_last_mouse_state.alt = mm->get_alt(); @@ -477,7 +451,12 @@ void Viewport::_notification(int p_what) { Ref<InputEventMouseButton> mb = ev; if (mb.is_valid()) { + pos = mb->get_position(); + is_mouse = true; + + 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(); @@ -487,6 +466,11 @@ void Viewport::_notification(int p_what) { 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)); + + // 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; + } } } @@ -539,40 +523,51 @@ void Viewport::_notification(int p_what) { if (res[i].collider_id && res[i].collider) { CollisionObject2D *co = Object::cast_to<CollisionObject2D>(res[i].collider); if (co) { - - Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); - if (!F) { - F = physics_2d_mouseover.insert(res[i].collider_id, frame); - co->_mouse_enter(); - } else { - F->get() = frame; + bool send_event = true; + if (is_mouse) { + Map<ObjectID, uint64_t>::Element *F = physics_2d_mouseover.find(res[i].collider_id); + + if (!F) { + 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; + } + } } - co->_input_event(this, ev, res[i].shape); + if (send_event) { + co->_input_event(this, ev, res[i].shape); + } } } } } - List<Map<ObjectID, uint64_t>::Element *> to_erase; + 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) { + 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(); + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + if (co) { + co->_mouse_exit(); + } } + to_erase.push_back(E); } - to_erase.push_back(E); } - } - while (to_erase.size()) { - physics_2d_mouseover.erase(to_erase.front()->get()); - to_erase.pop_front(); + while (to_erase.size()) { + physics_2d_mouseover.erase(to_erase.front()->get()); + to_erase.pop_front(); + } } } @@ -583,7 +578,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_capture)); if (co) { - _collision_object_input_event(co, camera, ev, Vector3(), Vector3(), 0, discard_empty_motion); + _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 = 0; @@ -601,7 +596,7 @@ void Viewport::_notification(int p_what) { if (last_id) { if (ObjectDB::get_instance(last_id) && last_object) { //good, exists - _collision_object_input_event(last_object, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _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; } @@ -624,7 +619,7 @@ void Viewport::_notification(int p_what) { CollisionObject *co = Object::cast_to<CollisionObject>(result.collider); if (co) { - _collision_object_input_event(co, camera, ev, result.position, result.normal, result.shape, discard_empty_motion); + _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; @@ -634,42 +629,41 @@ void Viewport::_notification(int p_what) { } } - if (mm.is_valid()) { - _test_new_mouseover(new_collider); - } - } + if (is_mouse && new_collider != physics_object_over) { - last_pos = pos; - } - } - } + if (physics_object_over) { - if (!motion_tested && camera && physics_has_last_mousepos) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); + if (co) { + co->_mouse_exit(); + } + } - //test anyway for mouseenter/exit because objects might move - Vector3 from = camera->project_ray_origin(physics_last_mousepos); - Vector3 dir = camera->project_ray_normal(physics_last_mousepos); + if (new_collider) { - PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space()); - if (space) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(new_collider)); + if (co) { + co->_mouse_enter(); + } + } - bool col = space->intersect_ray(from, from + dir * 10000, result, Set<RID>(), 0xFFFFFFFF, true, true, true); - ObjectID new_collider = 0; - if (col) { - CollisionObject *co = Object::cast_to<CollisionObject>(result.collider); - if (co) { - new_collider = result.collider_id; + physics_object_over = new_collider; + } } - } - _test_new_mouseover(new_collider); + last_pos = pos; + } } #endif } } } break; + case SceneTree::NOTIFICATION_WM_MOUSE_EXIT: case SceneTree::NOTIFICATION_WM_FOCUS_OUT: { + + _drop_physics_mouseover(); + if (gui.mouse_focus) { //if mouse is being pressed, send a release event _drop_mouse_focus(); @@ -1486,7 +1480,8 @@ void Viewport::_gui_show_tooltip() { gui.tooltip_popup->set_as_toplevel(true); //gui.tooltip_popup->hide(); - Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_popup->get_minimum_size()); + Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset"); + Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_minimum_size()); Rect2 vr = gui.tooltip_popup->get_viewport_rect(); if (r.size.x + r.position.x > vr.size.x) r.position.x = vr.size.x - r.size.x; @@ -2305,32 +2300,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { if (from && p_event->is_pressed()) { Control *next = NULL; - if (p_event->is_action("ui_focus_next")) { + if (p_event->is_action_pressed("ui_focus_next")) { next = from->find_next_valid_focus(); } - if (p_event->is_action("ui_focus_prev")) { + if (p_event->is_action_pressed("ui_focus_prev")) { next = from->find_prev_valid_focus(); } - if (!mods && p_event->is_action("ui_up")) { + if (!mods && p_event->is_action_pressed("ui_up")) { next = from->_get_focus_neighbour(MARGIN_TOP); } - if (!mods && p_event->is_action("ui_left")) { + if (!mods && p_event->is_action_pressed("ui_left")) { next = from->_get_focus_neighbour(MARGIN_LEFT); } - if (!mods && p_event->is_action("ui_right")) { + if (!mods && p_event->is_action_pressed("ui_right")) { next = from->_get_focus_neighbour(MARGIN_RIGHT); } - if (!mods && p_event->is_action("ui_down")) { + if (!mods && p_event->is_action_pressed("ui_down")) { next = from->_get_focus_neighbour(MARGIN_BOTTOM); } @@ -2570,6 +2565,31 @@ void Viewport::_drop_mouse_focus() { } } +void Viewport::_drop_physics_mouseover() { + + physics_has_last_mousepos = false; + + while (physics_2d_mouseover.size()) { + Object *o = ObjectDB::get_instance(physics_2d_mouseover.front()->key()); + if (o) { + CollisionObject2D *co = Object::cast_to<CollisionObject2D>(o); + co->_mouse_exit(); + } + physics_2d_mouseover.erase(physics_2d_mouseover.front()); + } + +#ifndef _3D_DISABLED + if (physics_object_over) { + CollisionObject *co = Object::cast_to<CollisionObject>(ObjectDB::get_instance(physics_object_over)); + if (co) { + co->_mouse_exit(); + } + } + + physics_object_over = physics_object_capture = 0; +#endif +} + List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) { gui.modal_stack.push_back(p_control); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index b8b5bf07a7..d67b4ac348 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -221,12 +221,11 @@ private: } physics_last_mouse_state; - void _collision_object_input_event(CollisionObject *p_object, Camera *p_camera, const Ref<InputEvent> &p_input_event, const Vector3 &p_pos, const Vector3 &p_normal, int p_shape, bool p_discard_empty_motion); + void _collision_object_input_event(CollisionObject *p_object, Camera *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; - void _test_new_mouseover(ObjectID new_collider); Map<ObjectID, uint64_t> physics_2d_mouseover; Ref<World2D> world_2d; @@ -384,6 +383,7 @@ private: void _canvas_layer_remove(CanvasLayer *p_canvas_layer); void _drop_mouse_focus(); + void _drop_physics_mouseover(); void _update_canvas_items(Node *p_node); diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 3eb16c544c..f73914b186 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -2638,6 +2638,7 @@ void Animation::copy_track(int p_track, Ref<Animation> p_to_animation) { p_to_animation->track_set_enabled(dst_track, track_is_enabled(p_track)); p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(p_track)); p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(p_track)); + p_to_animation->value_track_set_update_mode(dst_track, value_track_get_update_mode(p_track)); for (int i = 0; i < track_get_key_count(p_track); i++) { p_to_animation->track_insert_key(dst_track, track_get_key_time(p_track, i), track_get_key_value(p_track, i), track_get_key_transition(p_track, i)); } diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp index a89cf108bc..4b3e392013 100644 --- a/scene/resources/audio_stream_sample.cpp +++ b/scene/resources/audio_stream_sample.cpp @@ -515,10 +515,10 @@ PoolVector<uint8_t> AudioStreamSample::get_data() const { return pv; } -void AudioStreamSample::save_to_wav(String p_path) { +Error AudioStreamSample::save_to_wav(const String &p_path) { if (format == AudioStreamSample::FORMAT_IMA_ADPCM) { WARN_PRINTS("Saving IMA_ADPC samples are not supported yet"); - return; + return ERR_UNAVAILABLE; } int sub_chunk_2_size = data_bytes; //Subchunk2Size = Size of data in bytes @@ -544,8 +544,9 @@ void AudioStreamSample::save_to_wav(String p_path) { file_path += ".wav"; } - Error err; - FileAccess *file = FileAccess::open(file_path, FileAccess::WRITE, &err); //Overrides existing file if present + FileAccessRef file = FileAccess::open(file_path, FileAccess::WRITE); //Overrides existing file if present + + ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE); // Create WAV Header file->store_string("RIFF"); //ChunkID @@ -583,6 +584,8 @@ void AudioStreamSample::save_to_wav(String p_path) { } file->close(); + + return OK; } Ref<AudioStreamPlayback> AudioStreamSample::instance_playback() { diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h index bd701ddd12..d4c5511f34 100644 --- a/scene/resources/audio_stream_sample.h +++ b/scene/resources/audio_stream_sample.h @@ -141,7 +141,7 @@ public: void set_data(const PoolVector<uint8_t> &p_data); PoolVector<uint8_t> get_data() const; - void save_to_wav(String p_path); + Error save_to_wav(const String &p_path); virtual Ref<AudioStreamPlayback> instance_playback(); virtual String get_stream_name() const; diff --git a/scene/resources/bit_map.cpp b/scene/resources/bit_map.cpp index d2e4d28b44..55264bcdf9 100644 --- a/scene/resources/bit_map.cpp +++ b/scene/resources/bit_map.cpp @@ -96,7 +96,7 @@ int BitMap::get_true_bit_count() const { const uint8_t *d = bitmask.ptr(); int c = 0; - //fast, almot branchless version + //fast, almost branchless version for (int i = 0; i < ds; i++) { @@ -106,6 +106,7 @@ int BitMap::get_true_bit_count() const { c += (d[i] & (1 << 4)) >> 4; c += (d[i] & (1 << 3)) >> 3; c += (d[i] & (1 << 2)) >> 2; + c += (d[i] & (1 << 1)) >> 1; c += d[i] & 1; } diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index c5125d576d..d40a5dee2e 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -56,6 +56,8 @@ bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) { set_item_preview(idx, p_value); else if (what == "navmesh") set_item_navmesh(idx, p_value); + else if (what == "navmesh_transform") + set_item_navmesh_transform(idx, p_value); else return false; @@ -80,6 +82,8 @@ bool MeshLibrary::_get(const StringName &p_name, Variant &r_ret) const { r_ret = _get_item_shapes(idx); else if (what == "navmesh") r_ret = get_item_navmesh(idx); + else if (what == "navmesh_transform") + r_ret = get_item_navmesh_transform(idx); else if (what == "preview") r_ret = get_item_preview(idx); else @@ -95,8 +99,10 @@ void MeshLibrary::_get_property_list(List<PropertyInfo> *p_list) const { String name = "item/" + itos(E->key()) + "/"; p_list->push_back(PropertyInfo(Variant::STRING, name + "name")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "mesh_transform")); p_list->push_back(PropertyInfo(Variant::ARRAY, name + "shapes")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "navmesh", PROPERTY_HINT_RESOURCE_TYPE, "NavigationMesh")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM, name + "navmesh_transform")); p_list->push_back(PropertyInfo(Variant::OBJECT, name + "preview", PROPERTY_HINT_RESOURCE_TYPE, "Texture", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_EDITOR_HELPER)); } } @@ -116,6 +122,7 @@ void MeshLibrary::set_item_name(int p_item, const String &p_name) { emit_changed(); _change_notify(); } + void MeshLibrary::set_item_mesh(int p_item, const Ref<Mesh> &p_mesh) { ERR_FAIL_COND(!item_map.has(p_item)); @@ -145,6 +152,15 @@ void MeshLibrary::set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navm _change_notify(); } +void MeshLibrary::set_item_navmesh_transform(int p_item, const Transform &p_transform) { + + ERR_FAIL_COND(!item_map.has(p_item)); + item_map[p_item].navmesh_transform = p_transform; + notify_change_to_owners(); + emit_changed(); + _change_notify(); +} + void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { ERR_FAIL_COND(!item_map.has(p_item)); @@ -152,11 +168,13 @@ void MeshLibrary::set_item_preview(int p_item, const Ref<Texture> &p_preview) { emit_changed(); _change_notify(); } + String MeshLibrary::get_item_name(int p_item) const { ERR_FAIL_COND_V(!item_map.has(p_item), ""); return item_map[p_item].name; } + Ref<Mesh> MeshLibrary::get_item_mesh(int p_item) const { ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Mesh>()); @@ -175,6 +193,12 @@ Ref<NavigationMesh> MeshLibrary::get_item_navmesh(int p_item) const { return item_map[p_item].navmesh; } +Transform MeshLibrary::get_item_navmesh_transform(int p_item) const { + + ERR_FAIL_COND_V(!item_map.has(p_item), Transform()); + return item_map[p_item].navmesh_transform; +} + Ref<Texture> MeshLibrary::get_item_preview(int p_item) const { ERR_FAIL_COND_V(!item_map.has(p_item), Ref<Texture>()); @@ -268,11 +292,13 @@ void MeshLibrary::_bind_methods() { ClassDB::bind_method(D_METHOD("set_item_name", "id", "name"), &MeshLibrary::set_item_name); ClassDB::bind_method(D_METHOD("set_item_mesh", "id", "mesh"), &MeshLibrary::set_item_mesh); ClassDB::bind_method(D_METHOD("set_item_navmesh", "id", "navmesh"), &MeshLibrary::set_item_navmesh); + ClassDB::bind_method(D_METHOD("set_item_navmesh_transform", "id", "navmesh"), &MeshLibrary::set_item_navmesh_transform); ClassDB::bind_method(D_METHOD("set_item_shapes", "id", "shapes"), &MeshLibrary::_set_item_shapes); ClassDB::bind_method(D_METHOD("set_item_preview", "id", "texture"), &MeshLibrary::set_item_preview); ClassDB::bind_method(D_METHOD("get_item_name", "id"), &MeshLibrary::get_item_name); ClassDB::bind_method(D_METHOD("get_item_mesh", "id"), &MeshLibrary::get_item_mesh); ClassDB::bind_method(D_METHOD("get_item_navmesh", "id"), &MeshLibrary::get_item_navmesh); + ClassDB::bind_method(D_METHOD("get_item_navmesh_transform", "id"), &MeshLibrary::get_item_navmesh_transform); ClassDB::bind_method(D_METHOD("get_item_shapes", "id"), &MeshLibrary::_get_item_shapes); ClassDB::bind_method(D_METHOD("get_item_preview", "id"), &MeshLibrary::get_item_preview); ClassDB::bind_method(D_METHOD("remove_item", "id"), &MeshLibrary::remove_item); diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h index 849a0577eb..4ae4fc6483 100644 --- a/scene/resources/mesh_library.h +++ b/scene/resources/mesh_library.h @@ -52,6 +52,7 @@ public: Ref<Mesh> mesh; Vector<ShapeData> shapes; Ref<Texture> preview; + Transform navmesh_transform; Ref<NavigationMesh> navmesh; }; @@ -72,11 +73,13 @@ public: void set_item_name(int p_item, const String &p_name); void set_item_mesh(int p_item, const Ref<Mesh> &p_mesh); void set_item_navmesh(int p_item, const Ref<NavigationMesh> &p_navmesh); + void set_item_navmesh_transform(int p_item, const Transform &p_transform); void set_item_shapes(int p_item, const Vector<ShapeData> &p_shapes); void set_item_preview(int p_item, const Ref<Texture> &p_preview); String get_item_name(int p_item) const; Ref<Mesh> get_item_mesh(int p_item) const; Ref<NavigationMesh> get_item_navmesh(int p_item) const; + Transform get_item_navmesh_transform(int p_item) const; Vector<ShapeData> get_item_shapes(int p_item) const; Ref<Texture> get_item_preview(int p_item) const; diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index 210fbe9f20..b6efca9acc 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1645,7 +1645,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } } - f->store_string("\n"); + if (E->next()) + f->store_line(String()); } if (packed_scene.is_valid()) { @@ -1714,7 +1715,8 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r f->store_string(_valprop(String(state->get_node_property_name(i, j))) + " = " + vars + "\n"); } - f->store_line(String()); + if (i < state->get_node_count() - 1) + f->store_line(String()); } for (int i = 0; i < state->get_connection_count(); i++) { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 08b2a05d43..3ca2b56d08 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -842,6 +842,12 @@ void StreamTexture::reload_from_file() { load(path); } +void StreamTexture::_validate_property(PropertyInfo &property) const { + if (property.name == "flags") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} + void StreamTexture::_bind_methods() { ClassDB::bind_method(D_METHOD("load", "path"), &StreamTexture::load); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 21d3782897..281a33929c 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -203,6 +203,7 @@ private: protected: static void _bind_methods(); + void _validate_property(PropertyInfo &property) const; public: typedef void (*TextureFormatRequestCallback)(const Ref<StreamTexture> &); |