diff options
Diffstat (limited to 'scene')
61 files changed, 683 insertions, 469 deletions
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index b4de12b113..c5ac4e1a05 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -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; @@ -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 } } @@ -610,7 +611,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 +622,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,7 +633,9 @@ 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 { diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index 39d7705226..38198c496e 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -41,13 +41,13 @@ 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); @@ -211,6 +218,8 @@ void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { _build_polygon(); _update_in_shape_owner(); } + update(); + update_configuration_warning(); } CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const { @@ -241,11 +250,27 @@ String CollisionPolygon2D::get_configuration_warning() const { 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.is_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; diff --git a/scene/2d/cpu_particles_2d.cpp b/scene/2d/cpu_particles_2d.cpp index 0e51264171..48acee1bc4 100644 --- a/scene/2d/cpu_particles_2d.cpp +++ b/scene/2d/cpu_particles_2d.cpp @@ -1032,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; } } diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index f4f08674c9..7d9cdd52ac 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -49,19 +49,9 @@ void Joint2D::_disconnect_signals() { } } -void Joint2D::_body_exit_tree(const ObjectID &p_body_id) { +void Joint2D::_body_exit_tree() { _disconnect_signals(); - Object *object = ObjectDB::get_instance(p_body_id); - PhysicsBody2D *body = Object::cast_to<PhysicsBody2D>(object); - ERR_FAIL_NULL(body); - RID body_rid = body->get_rid(); - if (ba == body_rid) { - a = NodePath(); - } - if (bb == body_rid) { - b = NodePath(); - } - _update_joint(); + _update_joint(true); } void Joint2D::_update_joint(bool p_only_free) { @@ -142,8 +132,8 @@ 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), make_binds(body_a->get_instance_id())); - body_b->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint2D::_body_exit_tree), make_binds(body_b->get_instance_id())); + 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); } diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index 3607a6c176..08e02ee29d 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -51,7 +51,7 @@ class Joint2D : public Node2D { protected: void _disconnect_signals(); - void _body_exit_tree(const ObjectID &p_body_id); + void _body_exit_tree(); void _update_joint(bool p_only_free = false); void _notification(int p_what); diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index ecc05fb931..a60a32f1d2 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -88,6 +88,12 @@ bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toler } return Geometry2D::is_point_in_polygon(p_point - get_offset(), polygon2d); } + +void Polygon2D::_validate_property(PropertyInfo &property) const { + if (!invert && property.name == "invert_border") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} #endif void Polygon2D::_skeleton_bone_setup_changed() { @@ -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 { diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h index ab01a4ffd0..43a66aad13 100644 --- a/scene/2d/polygon_2d.h +++ b/scene/2d/polygon_2d.h @@ -72,6 +72,10 @@ class Polygon2D : public Node2D { void _skeleton_bone_setup_changed(); +#ifdef TOOLS_ENABLED + void _validate_property(PropertyInfo &property) const override; +#endif + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 2cc3a74270..50625a0f39 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -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.0; - 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() { diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index dab3302e25..984c6bda49 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -51,6 +51,8 @@ class RayCast2D : public Node2D { bool collide_with_areas = false; bool collide_with_bodies = true; + void _draw_debug_shape(); + protected: void _notification(int p_what); void _update_raycast_state(); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index dde9790b44..31040020dd 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -206,6 +206,7 @@ void Sprite2D::set_region(bool p_region) { region = p_region; update(); + notify_property_list_changed(); } bool Sprite2D::is_region() const { @@ -383,6 +384,10 @@ void Sprite2D::_validate_property(PropertyInfo &property) const { if (property.name == "frame_coords") { property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } + + if (!region && (property.name == "region_rect" || property.name == "region_filter_clip")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } } void Sprite2D::_texture_changed() { diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp index 578ea823f0..402e2b8f40 100644 --- a/scene/3d/baked_lightmap.cpp +++ b/scene/3d/baked_lightmap.cpp @@ -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) { diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index b7da4822e2..849ef7a2bf 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -30,6 +30,7 @@ #include "collision_object_3d.h" +#include "mesh_instance_3d.h" #include "scene/scene_string_names.h" #include "servers/physics_server_3d.h" @@ -110,6 +111,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()) { + 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 +178,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 +227,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 +263,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 +287,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 +296,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 +324,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()) { diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h index b7473ca12a..fe20176984 100644 --- a/scene/3d/collision_object_3d.h +++ b/scene/3d/collision_object_3d.h @@ -45,6 +45,7 @@ class CollisionObject3D : public Node3D { Object *owner = nullptr; Transform xform; struct ShapeBase { + Node *debug_shape = nullptr; Ref<Shape3D> shape; int index = 0; }; @@ -60,8 +61,12 @@ class CollisionObject3D : public Node3D { 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); @@ -72,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_shape_3d.cpp b/scene/3d/collision_shape_3d.cpp index 914c8eab7a..242d82ab4c 100644 --- a/scene/3d/collision_shape_3d.cpp +++ b/scene/3d/collision_shape_3d.cpp @@ -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) { @@ -163,8 +160,6 @@ 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"); } @@ -224,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 f55c09ffaa..5512417f75 100644 --- a/scene/3d/collision_shape_3d.h +++ b/scene/3d/collision_shape_3d.h @@ -43,14 +43,10 @@ class CollisionShape3D : public Node3D { uint32_t owner_id = 0; CollisionObject3D *parent = nullptr; - Node *debug_shape = nullptr; - bool debug_shape_dirty; - void resource_changed(RES res); 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/decal.cpp b/scene/3d/decal.cpp index 0f10f2b85f..b5eab35605 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -109,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 { @@ -153,6 +154,14 @@ Vector<Face3> Decal::get_faces(uint32_t p_usage_flags) const { return Vector<Face3>(); } +#ifdef TOOLS_ENABLED +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; + } +} +#endif + 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); diff --git a/scene/3d/decal.h b/scene/3d/decal.h index 095579d775..20d86ee16c 100644 --- a/scene/3d/decal.h +++ b/scene/3d/decal.h @@ -62,6 +62,10 @@ private: float distance_fade_begin = 10.0; float distance_fade_length = 1.0; +#ifdef TOOLS_ENABLED + void _validate_property(PropertyInfo &property) const override; +#endif + protected: static void _bind_methods(); diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp index 8a8bfe50b9..43f820e5d4 100644 --- a/scene/3d/gi_probe.cpp +++ b/scene/3d/gi_probe.cpp @@ -415,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); diff --git a/scene/3d/light_3d.cpp b/scene/3d/light_3d.cpp index b0a10b5547..87f54022b3 100644 --- a/scene/3d/light_3d.cpp +++ b/scene/3d/light_3d.cpp @@ -65,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 { @@ -202,6 +204,10 @@ bool Light3D::is_editor_only() const { } void Light3D::_validate_property(PropertyInfo &property) const { + if (!shadow && (property.name == "shadow_color" || 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_blur")) { + property.usage = PROPERTY_USAGE_NOEDITOR; + } + if (get_light_type() == RS::LIGHT_DIRECTIONAL && property.name == "light_size") { property.usage = 0; } diff --git a/scene/3d/physics_joint_3d.cpp b/scene/3d/physics_joint_3d.cpp index 0463bed9d6..de9c75621b 100644 --- a/scene/3d/physics_joint_3d.cpp +++ b/scene/3d/physics_joint_3d.cpp @@ -46,24 +46,15 @@ void Joint3D::_disconnect_signals() { } } -void Joint3D::_body_exit_tree(const ObjectID &p_body_id) { +void Joint3D::_body_exit_tree() { _disconnect_signals(); - Object *object = ObjectDB::get_instance(p_body_id); - PhysicsBody3D *body = Object::cast_to<PhysicsBody3D>(object); - ERR_FAIL_NULL(body); - RID body_rid = body->get_rid(); - if (ba == body_rid) { - a = NodePath(); - } - if (bb == body_rid) { - b = NodePath(); - } - _update_joint(); + _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(); @@ -133,12 +124,12 @@ void Joint3D::_update_joint(bool p_only_free) { if (body_a) { ba = body_a->get_rid(); - body_a->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &Joint3D::_body_exit_tree), make_binds(body_a->get_instance_id())); + 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), make_binds(body_b->get_instance_id())); + 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); diff --git a/scene/3d/physics_joint_3d.h b/scene/3d/physics_joint_3d.h index 8d0a16e432..f624ba602b 100644 --- a/scene/3d/physics_joint_3d.h +++ b/scene/3d/physics_joint_3d.h @@ -51,7 +51,7 @@ class Joint3D : public Node3D { protected: void _disconnect_signals(); - void _body_exit_tree(const ObjectID &p_body_id); + void _body_exit_tree(); void _update_joint(bool p_only_free = false); void _notification(int p_what); diff --git a/scene/3d/ray_cast_3d.cpp b/scene/3d/ray_cast_3d.cpp index bfe79f15f5..465de2cb47 100644 --- a/scene/3d/ray_cast_3d.cpp +++ b/scene/3d/ray_cast_3d.cpp @@ -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,6 +149,9 @@ 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); } else { @@ -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; +} - 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)); +const Vector<Vector3> &RayCast3D::get_debug_line_vertices() const { + return debug_line_vertices; +} + +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, hightlight collision with green color + color = Color(0.0, 1.0, 0.0, color.a); + } else { + // Else, hightlight 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; @@ -353,26 +455,28 @@ void RayCast3D::_update_debug_shape() { return; } - Vector<Vector3> verts; - verts.push_back(Vector3()); - verts.push_back(target_position); + _update_debug_shape_vertices(); - if (mesh->get_surface_count() == 0) { - Array a; - a.resize(Mesh::ARRAY_MAX); - a[Mesh::ARRAY_VERTEX] = verts; + mesh->clear_surfaces(); - uint32_t flags = Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; + Array a; + a.resize(Mesh::ARRAY_MAX); + uint32_t flags = 0; + int surface_count = 0; + + 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(0, debug_material); - } else { - Vector<uint8_t> byte_array; - int array_size = sizeof(Vector3) * verts.size(); - byte_array.resize(array_size); - copymem(byte_array.ptrw(), verts.ptr(), array_size); + mesh->surface_set_material(surface_count, debug_material); + ++surface_count; + } - RS::get_singleton()->mesh_surface_update_region(mesh->get_rid(), 0, 0, byte_array); + 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; } } diff --git a/scene/3d/ray_cast_3d.h b/scene/3d/ray_cast_3d.h index ae92189527..968cede9f2 100644 --- a/scene/3d/ray_cast_3d.h +++ b/scene/3d/ray_cast_3d.h @@ -51,9 +51,15 @@ class RayCast3D : public Node3D { 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 = false; @@ -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/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index cb2df9130f..f881181ccd 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -518,6 +518,7 @@ void Sprite3D::set_region(bool p_region) { region = p_region; _queue_update(); + notify_property_list_changed(); } bool Sprite3D::is_region() const { @@ -623,6 +624,12 @@ void Sprite3D::_validate_property(PropertyInfo &property) const { if (property.name == "frame_coords") { property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS; } + +#ifdef TOOLS_ENABLED + if (!region && property.name == "region_rect") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +#endif } void Sprite3D::_bind_methods() { diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 9b98f3d031..eb35979a47 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -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()) { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index 88c02be0bc..142c0c65e0 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -107,6 +107,7 @@ private: float speed_scale = 1.0; mutable int pending_update = 0; int uid = 0; + bool was_stopped = false; List<InterpolateData> interpolates; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 0c104bf318..bff3024e38 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -93,7 +93,7 @@ void Control::_edit_set_state(const Dictionary &p_state) { void Control::_edit_set_position(const Point2 &p_position) { #ifdef TOOLS_ENABLED - set_position(p_position, CanvasItemEditor::get_singleton()->is_anchors_mode_enabled()); + 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); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 70015bcf88..331f0380c5 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -530,14 +530,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; } } @@ -551,7 +551,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) { if (mb.is_valid() && mb->get_button_index() == 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) { @@ -560,7 +560,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()) { @@ -602,7 +602,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()) { @@ -651,11 +651,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) { @@ -666,7 +666,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(); @@ -678,7 +678,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(); @@ -760,6 +760,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; @@ -1209,7 +1214,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; } @@ -1553,7 +1558,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) { diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index ba08aae8e3..3e8ebd2429 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -255,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; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index cbadf818cd..f1d9de255a 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -136,6 +136,7 @@ private: bool creating = false; bool doubleclick = false; bool drag_attempt = false; + uint64_t last_dblclk = 0; } selection; struct TextOperation { diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index a79c633502..682584d73f 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -1578,11 +1578,11 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) { if (k->is_pressed()) { bool handled = false; - if (k->is_action("ui_pageup") && vscroll->is_visible_in_tree()) { + 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_pagedown") && vscroll->is_visible_in_tree()) { + if (k->is_action("ui_page_down") && vscroll->is_visible_in_tree()) { vscroll->set_value(vscroll->get_value() + vscroll->get_page()); handled = true; } diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp index 8b07299e30..2239226c78 100644 --- a/scene/gui/slider.cpp +++ b/scene/gui/slider.cpp @@ -73,8 +73,10 @@ void Slider::_gui_input(Ref<InputEvent> p_event) { } } else if (scrollable) { if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_UP) { + grab_focus(); set_value(get_value() + get_step()); } else if (mb->is_pressed() && mb->get_button_index() == BUTTON_WHEEL_DOWN) { + grab_focus(); set_value(get_value() - get_step()); } } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 2c9720e4b6..d82cc98e01 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -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; @@ -136,12 +144,7 @@ void SpinBox::_gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == 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; } @@ -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) { diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 4c3adf30e8..e116adb64c 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -43,6 +43,7 @@ class SpinBox : public Range { Timer *range_click_timer; void _range_click_timeout(); + void _release_mouse(); void _text_entered(const String &p_string); virtual void _value_changed(double) override; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 36aa18417d..5a7901c11b 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -412,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. diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 17fe001b5d..6ac4d7fd2f 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3354,10 +3354,10 @@ 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 (selected_col == p_column) { + selected_col = -1; + } } if (select_mode == SELECT_MULTI || select_mode == SELECT_SINGLE) { diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 91daa08ff8..d9b29daf26 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -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,14 @@ void CanvasLayer::_update_follow_viewport(bool p_force_exit) { } } +#ifdef TOOLS_ENABLED +void CanvasLayer::_validate_property(PropertyInfo &property) const { + if (!follow_viewport && property.name == "follow_viewport_scale") { + property.usage = PROPERTY_USAGE_NOEDITOR; + } +} +#endif + 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); diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h index 181d1dd659..b20b291367 100644 --- a/scene/main/canvas_layer.h +++ b/scene/main/canvas_layer.h @@ -61,6 +61,10 @@ class CanvasLayer : public Node { void _update_locrotscale(); void _update_follow_viewport(bool p_force_exit = false); +#ifdef TOOLS_ENABLED + void _validate_property(PropertyInfo &property) const override; +#endif + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp index ce7d6ef13c..71c372aec2 100644 --- a/scene/main/http_request.cpp +++ b/scene/main/http_request.cpp @@ -387,6 +387,9 @@ bool HTTPRequest::_update_connection() { } client->poll(); + if (client->get_status() != HTTPClient::STATUS_BODY) { + return false; + } PackedByteArray chunk = client->read_response_body_chunk(); downloaded.add(chunk.size()); @@ -415,6 +418,7 @@ bool HTTPRequest::_update_connection() { } 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; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 893621fbc4..9d8c7981e6 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -1976,7 +1976,7 @@ bool Node::is_editable_instance(const Node *p_node) const { 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), 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; @@ -2052,6 +2052,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; @@ -2267,74 +2268,6 @@ void Node::remap_nested_resources(RES p_resource, const Map<RES, RES> &p_resourc } #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; - } - - 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()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { - continue; - } - String name = E->get().name; - - Variant value = get(name).duplicate(true); - - node->set(name, value); - } - - 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); - } - - node->set_name(get_name()); - p_new_parent->add_child(node); - - Node *owner = get_owner(); - - if (p_reown_map.has(owner)) { - owner = p_reown_map[owner]; - } - - 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); - } - } - } - - 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 @@ -2389,49 +2322,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); diff --git a/scene/main/node.h b/scene/main/node.h index 249a0ff86e..d47d271a10 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -173,7 +173,6 @@ private: 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; @@ -366,7 +365,6 @@ 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; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index b10e23ac07..9aaddfd373 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -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); @@ -534,12 +535,7 @@ void SceneTree::finalize() { } 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; } @@ -1205,7 +1201,7 @@ void SceneTree::_bind_methods() { 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); @@ -1350,6 +1346,8 @@ SceneTree::SceneTree() { 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); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index c2280c747b..a2f2adb8f8 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -245,7 +245,7 @@ public: 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_process_time() const { return process_time; } diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 54b670df6c..40b85e6d7b 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -1770,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) { @@ -1920,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 @@ -1935,9 +1939,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) { _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(); @@ -2034,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; } @@ -2177,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; @@ -2453,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) { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 2a0026a561..0f11e6fb19 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -357,7 +357,7 @@ private: Point2 drag_accum; bool drag_attempted = false; Variant drag_data; - Control *drag_preview = nullptr; + ObjectID drag_preview_id; float tooltip_timer = -1.0; float tooltip_delay = 0.0; Transform2D focus_inv_xform; @@ -415,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(); diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 8198fa41c5..d697a1a5dd 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -826,6 +826,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; } @@ -1035,6 +1038,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); diff --git a/scene/resources/animation.h b/scene/resources/animation.h index fd22cc445c..66bc71c834 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -70,7 +70,7 @@ private: bool loop_wrap = true; NodePath path; // path to something bool imported = false; - bool enabled = false; + bool enabled = true; Track() {} virtual ~Track() {} }; diff --git a/scene/resources/camera_effects.cpp b/scene/resources/camera_effects.cpp index 4038338e1e..00312fc7b2 100644 --- a/scene/resources/camera_effects.cpp +++ b/scene/resources/camera_effects.cpp @@ -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,16 @@ void CameraEffects::_update_override_exposure() { // Private methods, constructor and destructor +#ifdef TOOLS_ENABLED +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; + } +} +#endif + void CameraEffects::_bind_methods() { // DOF blur diff --git a/scene/resources/camera_effects.h b/scene/resources/camera_effects.h index 28aa6b8660..51fb2b6cf7 100644 --- a/scene/resources/camera_effects.h +++ b/scene/resources/camera_effects.h @@ -57,6 +57,10 @@ private: float override_exposure = 1.0; void _update_override_exposure(); +#ifdef TOOLS_ENABLED + void _validate_property(PropertyInfo &property) const override; +#endif + protected: static void _bind_methods(); diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index acf7319339..e5edba8a67 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -85,9 +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); - 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); + 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 { diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index a8a9c42fbd..f06bc4248d 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -79,9 +79,11 @@ void CircleShape2D::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); - 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); + 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() : diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index 7271614995..6e56f6e7fc 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -72,12 +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); - 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); + 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 { diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp index 6f6af93848..c04b271d81 100644 --- a/scene/resources/environment.cpp +++ b/scene/resources/environment.cpp @@ -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 { @@ -983,6 +984,7 @@ void Environment::_validate_property(PropertyInfo &property) const { "auto_exposure_", "ss_reflections_", "ssao_", + "sdfgi_", "glow_", "adjustment_", nullptr diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 062d921855..9931757cc4 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -1584,7 +1584,7 @@ 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) { + 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(); @@ -1650,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; } } @@ -1683,16 +1683,24 @@ 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 diff --git a/scene/resources/navigation_mesh.cpp b/scene/resources/navigation_mesh.cpp index 84f3c23f77..8c12f59a00 100644 --- a/scene/resources/navigation_mesh.cpp +++ b/scene/resources/navigation_mesh.cpp @@ -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(); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 5d351f51f7..ab8a4b7934 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -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) { diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index 0fd65d8c72..dc4c6dc2d7 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -47,23 +47,25 @@ Vector2 RectangleShape2D::get_size() const { } void RectangleShape2D::draw(const RID &p_to_rid, const Color &p_color) { - // 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; + 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); - } + 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_rect(p_to_rid, Rect2(-size * 0.5, size), p_color); - RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors); + RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, stroke_points, stroke_colors); + } } Rect2 RectangleShape2D::get_rect() const { diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index f8a5855d33..013b1ef1a9 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -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,6 +109,15 @@ 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; } diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index 7b00e7e426..14bdd60e4b 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -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/texture.cpp b/scene/resources/texture.cpp index 8cccf81659..d2bb1338d8 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -151,7 +151,7 @@ void ImageTexture::_reload_hook(const RID &p_hook) { } 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(); diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp index d6200059f6..a99c09e89c 100644 --- a/scene/resources/visual_shader_nodes.cpp +++ b/scene/resources/visual_shader_nodes.cpp @@ -2742,8 +2742,6 @@ int VisualShaderNodeClamp::get_input_port_count() const { VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_FLOAT: - return PORT_TYPE_SCALAR; case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; case OP_TYPE_VECTOR: @@ -2771,8 +2769,6 @@ int VisualShaderNodeClamp::get_output_port_count() const { VisualShaderNodeClamp::PortType VisualShaderNodeClamp::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_FLOAT: - return PORT_TYPE_SCALAR; case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; case OP_TYPE_VECTOR: @@ -2954,18 +2950,11 @@ int VisualShaderNodeStep::get_input_port_count() const { VisualShaderNodeStep::PortType VisualShaderNodeStep::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: - switch (p_port) { - case 0: - return PORT_TYPE_SCALAR; - case 1: - return PORT_TYPE_VECTOR; - default: - break; + if (p_port == 1) { + return PORT_TYPE_VECTOR; } break; default: @@ -2989,8 +2978,6 @@ int VisualShaderNodeStep::get_output_port_count() const { VisualShaderNodeStep::PortType VisualShaderNodeStep::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: @@ -3032,7 +3019,7 @@ void VisualShaderNodeStep::set_op_type(OpType p_op_type) { set_input_port_default_value(0, 0.0); // edge } if (op_type == OP_TYPE_SCALAR) { - set_input_port_default_value(1, 0.0); // x + set_input_port_default_value(1, Vector3(0.0, 0.0, 0.0)); // x } break; default: @@ -3085,20 +3072,11 @@ int VisualShaderNodeSmoothStep::get_input_port_count() const { VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: - switch (p_port) { - case 0: - return PORT_TYPE_SCALAR; // edge0 - case 1: - return PORT_TYPE_SCALAR; // edge1 - case 2: - return PORT_TYPE_VECTOR; // x - default: - break; + if (p_port == 2) { + return PORT_TYPE_VECTOR; // x } break; default: @@ -3124,8 +3102,6 @@ int VisualShaderNodeSmoothStep::get_output_port_count() const { VisualShaderNodeSmoothStep::PortType VisualShaderNodeSmoothStep::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: @@ -3319,16 +3295,11 @@ int VisualShaderNodeMix::get_input_port_count() const { VisualShaderNodeMix::PortType VisualShaderNodeMix::get_input_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: - if (p_port == 2) { - return PORT_TYPE_VECTOR; - } return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: if (p_port == 2) { - return PORT_TYPE_SCALAR; + break; } return PORT_TYPE_VECTOR; default: @@ -3353,8 +3324,6 @@ int VisualShaderNodeMix::get_output_port_count() const { VisualShaderNodeMix::PortType VisualShaderNodeMix::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_SCALAR: - return PORT_TYPE_SCALAR; case OP_TYPE_VECTOR: return PORT_TYPE_VECTOR; case OP_TYPE_VECTOR_SCALAR: @@ -4540,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; @@ -4923,8 +4890,6 @@ VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_input_port_type(int } if (p_port == 1 || p_port == 2) { switch (op_type) { - case OP_TYPE_FLOAT: - return PORT_TYPE_SCALAR; case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; case OP_TYPE_VECTOR: @@ -4959,8 +4924,6 @@ int VisualShaderNodeSwitch::get_output_port_count() const { VisualShaderNodeSwitch::PortType VisualShaderNodeSwitch::get_output_port_type(int p_port) const { switch (op_type) { - case OP_TYPE_FLOAT: - return PORT_TYPE_SCALAR; case OP_TYPE_INT: return PORT_TYPE_SCALAR_INT; case OP_TYPE_VECTOR: @@ -5238,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; @@ -5252,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 { @@ -5472,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 { |