diff options
Diffstat (limited to 'scene')
32 files changed, 608 insertions, 272 deletions
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index fc5e5cbba2..b38fbfe981 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -602,9 +602,7 @@ void CanvasItem::_notification(int p_what) { } global_invalid = true; } break; - case NOTIFICATION_DRAW: { - - } break; + case NOTIFICATION_DRAW: case NOTIFICATION_TRANSFORM_CHANGED: { } break; diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp index 9fe5fb98b6..6436b3878f 100644 --- a/scene/2d/line_builder.cpp +++ b/scene/2d/line_builder.cpp @@ -155,7 +155,7 @@ void LineBuilder::build() { texture_mode == Line2D::LINE_TEXTURE_STRETCH; if (distance_required) { total_distance = calculate_total_distance(points); - //Ajust totalDistance. + //Adjust totalDistance. // The line's outer length will be a little higher due to begin and end caps if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) { if (retrieve_curve) diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index e389d5f98f..678db85ff0 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -271,7 +271,7 @@ void NavigationPolygon::make_polygons_from_outlines() { struct Polygon p; - for (int i = 0; i < tp.GetNumPoints(); i++) { + for (int64_t i = 0; i < tp.GetNumPoints(); i++) { Map<Vector2, int>::Element *E = points.find(tp[i]); if (!E) { diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 9b6020e0fd..28f7243c44 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -1209,7 +1209,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_ return colliding; } -//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45. +//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 89072519d5..50ca466df3 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -149,12 +149,38 @@ Ref<Mesh> MeshInstance::get_mesh() const { void MeshInstance::_resolve_skeleton_path() { - if (skeleton_path.is_empty()) + Ref<SkinReference> new_skin_reference; + + if (!skeleton_path.is_empty()) { + Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path)); + if (skeleton) { + new_skin_reference = skeleton->register_skin(skin); + if (skin.is_null()) { + //a skin was created for us + skin = new_skin_reference->get_skin(); + _change_notify(); + } + } + } + + skin_ref = new_skin_reference; + + if (skin_ref.is_valid()) { + VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skin_ref->get_skeleton()); + } else { + VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), RID()); + } +} + +void MeshInstance::set_skin(const Ref<Skin> &p_skin) { + skin = p_skin; + if (!is_inside_tree()) return; + _resolve_skeleton_path(); +} - Skeleton *skeleton = Object::cast_to<Skeleton>(get_node(skeleton_path)); - if (skeleton) - VisualServer::get_singleton()->instance_attach_skeleton(get_instance(), skeleton->get_skeleton()); +Ref<Skin> MeshInstance::get_skin() const { + return skin; } void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) { @@ -365,6 +391,8 @@ void MeshInstance::_bind_methods() { ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance::get_mesh); ClassDB::bind_method(D_METHOD("set_skeleton_path", "skeleton_path"), &MeshInstance::set_skeleton_path); ClassDB::bind_method(D_METHOD("get_skeleton_path"), &MeshInstance::get_skeleton_path); + ClassDB::bind_method(D_METHOD("set_skin", "skin"), &MeshInstance::set_skin); + ClassDB::bind_method(D_METHOD("get_skin"), &MeshInstance::get_skin); ClassDB::bind_method(D_METHOD("get_surface_material_count"), &MeshInstance::get_surface_material_count); ClassDB::bind_method(D_METHOD("set_surface_material", "surface", "material"), &MeshInstance::set_surface_material); @@ -380,6 +408,7 @@ void MeshInstance::_bind_methods() { ClassDB::set_method_flags("MeshInstance", "create_debug_tangents", METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "skin", PROPERTY_HINT_RESOURCE_TYPE, "Skin"), "set_skin", "get_skin"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton"), "set_skeleton_path", "get_skeleton_path"); } diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h index 8b690b0c21..77ead75dd3 100644 --- a/scene/3d/mesh_instance.h +++ b/scene/3d/mesh_instance.h @@ -31,8 +31,10 @@ #ifndef MESH_INSTANCE_H #define MESH_INSTANCE_H +#include "scene/3d/skeleton.h" #include "scene/3d/visual_instance.h" #include "scene/resources/mesh.h" +#include "scene/resources/skin.h" class MeshInstance : public GeometryInstance { @@ -40,6 +42,8 @@ class MeshInstance : public GeometryInstance { protected: Ref<Mesh> mesh; + Ref<Skin> skin; + Ref<SkinReference> skin_ref; NodePath skeleton_path; struct BlendShapeTrack { @@ -70,6 +74,9 @@ public: void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; + void set_skin(const Ref<Skin> &p_skin); + Ref<Skin> get_skin() const; + void set_skeleton_path(const NodePath &p_skeleton); NodePath get_skeleton_path(); diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index 0756be5fc8..71040d2d68 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -1137,7 +1137,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_in return colliding; } -//so, if you pass 45 as limit, avoid numerical precision erros when angle is 45. +//so, if you pass 45 as limit, avoid numerical precision errors when angle is 45. #define FLOOR_ANGLE_THRESHOLD 0.01 Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_stop_on_slope, int p_max_slides, float p_floor_max_angle, bool p_infinite_inertia) { @@ -2182,7 +2182,7 @@ void PhysicalBone::_notification(int p_what) { void PhysicalBone::_direct_state_changed(Object *p_state) { - if (!simulate_physics) { + if (!simulate_physics || !_internal_simulate_physics) { return; } @@ -2205,7 +2205,7 @@ void PhysicalBone::_direct_state_changed(Object *p_state) { // Update skeleton if (parent_skeleton) { if (-1 != bone_id) { - parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse)); + parent_skeleton->set_bone_global_pose_override(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse), 1.0, true); } } } @@ -2716,7 +2716,6 @@ void PhysicalBone::_start_physics_simulation() { PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer()); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask()); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed"); - parent_skeleton->set_bone_ignore_animation(bone_id, true); _internal_simulate_physics = true; } @@ -2728,6 +2727,6 @@ void PhysicalBone::_stop_physics_simulation() { PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0); PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0); PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, ""); - parent_skeleton->set_bone_ignore_animation(bone_id, false); + parent_skeleton->set_bone_global_pose_override(bone_id, Transform(), 0.0, false); _internal_simulate_physics = false; } diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index e192e040f2..ead1e69f90 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -36,6 +36,34 @@ #include "scene/3d/physics_body.h" #include "scene/resources/surface_tool.h" +void SkinReference::_skin_changed() { + if (skeleton_node) { + skeleton_node->_make_dirty(); + } +} + +void SkinReference::_bind_methods() { + ClassDB::bind_method(D_METHOD("_skin_changed"), &SkinReference::_skin_changed); + ClassDB::bind_method(D_METHOD("get_skeleton"), &SkinReference::get_skeleton); + ClassDB::bind_method(D_METHOD("get_skin"), &SkinReference::get_skin); +} + +RID SkinReference::get_skeleton() const { + return skeleton; +} + +Ref<Skin> SkinReference::get_skin() const { + return skin; +} + +SkinReference::~SkinReference() { + if (skeleton_node) { + skeleton_node->skin_bindings.erase(this); + } + + VS::get_singleton()->free(skeleton); +} + bool Skeleton::_set(const StringName &p_path, const Variant &p_value) { String path = p_path; @@ -196,110 +224,77 @@ void Skeleton::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_WORLD: { - - VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); - - } break; - case NOTIFICATION_EXIT_WORLD: { - - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - - VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); - } break; case NOTIFICATION_UPDATE_SKELETON: { VisualServer *vs = VisualServer::get_singleton(); Bone *bonesptr = bones.ptrw(); int len = bones.size(); - vs->skeleton_allocate(skeleton, len); // if same size, nothing really happens - _update_process_order(); const int *order = process_order.ptr(); - // pose changed, rebuild cache of inverses - if (rest_global_inverse_dirty) { - - // calculate global rests and invert them - for (int i = 0; i < len; i++) { - Bone &b = bonesptr[order[i]]; - if (b.parent >= 0) - b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest; - else - b.rest_global_inverse = b.rest; - } - for (int i = 0; i < len; i++) { - Bone &b = bonesptr[order[i]]; - b.rest_global_inverse.affine_invert(); - } - - rest_global_inverse_dirty = false; - } - for (int i = 0; i < len; i++) { Bone &b = bonesptr[order[i]]; - if (b.disable_rest) { - if (b.enabled) { + if (b.global_pose_override_amount >= 0.999) { + b.pose_global = b.global_pose_override; + } else { + if (b.disable_rest) { + if (b.enabled) { - Transform pose = b.pose; - if (b.custom_pose_enable) { + Transform pose = b.pose; + if (b.parent >= 0) { - pose = b.custom_pose * pose; - } + b.pose_global = bonesptr[b.parent].pose_global * pose; + } else { - if (b.parent >= 0) { - - b.pose_global = bonesptr[b.parent].pose_global * pose; + b.pose_global = pose; + } } else { - b.pose_global = pose; - } - } else { - - if (b.parent >= 0) { + if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global; - } else { + b.pose_global = bonesptr[b.parent].pose_global; + } else { - b.pose_global = Transform(); + b.pose_global = Transform(); + } } - } - } else { - if (b.enabled) { + } else { + if (b.enabled) { - Transform pose = b.pose; - if (b.custom_pose_enable) { + Transform pose = b.pose; - pose = b.custom_pose * pose; - } + if (b.parent >= 0) { - if (b.parent >= 0) { + b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose); + } else { - b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose); + b.pose_global = b.rest * pose; + } } else { - b.pose_global = b.rest * pose; - } - } else { + if (b.parent >= 0) { - if (b.parent >= 0) { + b.pose_global = bonesptr[b.parent].pose_global * b.rest; + } else { - b.pose_global = bonesptr[b.parent].pose_global * b.rest; - } else { - - b.pose_global = b.rest; + b.pose_global = b.rest; + } } } + + if (b.global_pose_override_amount >= CMP_EPSILON) { + b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount); + } } - b.transform_final = b.pose_global * b.rest_global_inverse; - vs->skeleton_bone_set_transform(skeleton, order[i], b.transform_final); + if (b.global_pose_override_reset) { + b.global_pose_override_amount = 0.0; + } for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) { @@ -311,28 +306,37 @@ void Skeleton::_notification(int p_what) { } } + //update skins + for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { + + const Skin *skin = E->get()->skin.operator->(); + RID skeleton = E->get()->skeleton; + uint32_t bind_count = skin->get_bind_count(); + + if (E->get()->bind_count != bind_count) { + VS::get_singleton()->skeleton_allocate(skeleton, bind_count); + E->get()->bind_count = bind_count; + } + + for (uint32_t i = 0; i < bind_count; i++) { + uint32_t bone_index = skin->get_bind_bone(i); + ERR_CONTINUE(bone_index >= (uint32_t)len); + vs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i)); + } + } + dirty = false; } break; } } -Transform Skeleton::get_bone_transform(int p_bone) const { - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); - if (dirty) - const_cast<Skeleton *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); - return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse; -} - -void Skeleton::set_bone_global_pose(int p_bone, const Transform &p_pose) { +void Skeleton::set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent) { ERR_FAIL_INDEX(p_bone, bones.size()); - if (bones[p_bone].parent == -1) { - - set_bone_pose(p_bone, bones[p_bone].rest_global_inverse * p_pose); //fast - } else { - - set_bone_pose(p_bone, bones[p_bone].rest.affine_inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose)); //slow - } + bones.write[p_bone].global_pose_override_amount = p_amount; + bones.write[p_bone].global_pose_override = p_pose; + bones.write[p_bone].global_pose_override_reset = !p_persistent; + _make_dirty(); } Transform Skeleton::get_bone_global_pose(int p_bone) const { @@ -343,11 +347,6 @@ Transform Skeleton::get_bone_global_pose(int p_bone) const { return bones[p_bone].pose_global; } -RID Skeleton::get_skeleton() const { - - return skeleton; -} - // skeleton creation api void Skeleton::add_bone(const String &p_name) { @@ -362,8 +361,6 @@ void Skeleton::add_bone(const String &p_name) { b.name = p_name; bones.push_back(b); process_order_dirty = true; - - rest_global_inverse_dirty = true; _make_dirty(); update_gizmo(); } @@ -408,7 +405,6 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) { ERR_FAIL_COND(p_parent != -1 && (p_parent < 0)); bones.write[p_bone].parent = p_parent; - rest_global_inverse_dirty = true; process_order_dirty = true; _make_dirty(); } @@ -426,23 +422,11 @@ void Skeleton::unparent_bone_and_rest(int p_bone) { } bones.write[p_bone].parent = -1; - bones.write[p_bone].rest_global_inverse = bones[p_bone].rest.affine_inverse(); //same thing process_order_dirty = true; _make_dirty(); } -void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) { - ERR_FAIL_INDEX(p_bone, bones.size()); - bones.write[p_bone].ignore_animation = p_ignore; -} - -bool Skeleton::is_bone_ignore_animation(int p_bone) const { - - ERR_FAIL_INDEX_V(p_bone, bones.size(), false); - return bones[p_bone].ignore_animation; -} - void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) { ERR_FAIL_INDEX(p_bone, bones.size()); @@ -467,7 +451,6 @@ void Skeleton::set_bone_rest(int p_bone, const Transform &p_rest) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].rest = p_rest; - rest_global_inverse_dirty = true; _make_dirty(); } Transform Skeleton::get_bone_rest(int p_bone) const { @@ -482,7 +465,6 @@ void Skeleton::set_bone_enabled(int p_bone, bool p_enabled) { ERR_FAIL_INDEX(p_bone, bones.size()); bones.write[p_bone].enabled = p_enabled; - rest_global_inverse_dirty = true; _make_dirty(); } bool Skeleton::is_bone_enabled(int p_bone) const { @@ -529,7 +511,6 @@ void Skeleton::get_bound_child_nodes_to_bone(int p_bone, List<Node *> *p_bound) void Skeleton::clear_bones() { bones.clear(); - rest_global_inverse_dirty = true; process_order_dirty = true; _make_dirty(); @@ -552,23 +533,6 @@ Transform Skeleton::get_bone_pose(int p_bone) const { return bones[p_bone].pose; } -void Skeleton::set_bone_custom_pose(int p_bone, const Transform &p_custom_pose) { - - ERR_FAIL_INDEX(p_bone, bones.size()); - //ERR_FAIL_COND( !is_inside_scene() ); - - bones.write[p_bone].custom_pose_enable = (p_custom_pose != Transform()); - bones.write[p_bone].custom_pose = p_custom_pose; - - _make_dirty(); -} - -Transform Skeleton::get_bone_custom_pose(int p_bone) const { - - ERR_FAIL_INDEX_V(p_bone, bones.size(), Transform()); - return bones[p_bone].custom_pose; -} - void Skeleton::_make_dirty() { if (dirty) @@ -747,14 +711,66 @@ void Skeleton::physical_bones_remove_collision_exception(RID p_exception) { #endif // _3D_DISABLED -void Skeleton::set_use_bones_in_world_transform(bool p_enable) { - use_bones_in_world_transform = p_enable; - if (is_inside_tree()) { - VS::get_singleton()->skeleton_set_world_transform(skeleton, use_bones_in_world_transform, get_global_transform()); - } +void Skeleton::_skin_changed() { + _make_dirty(); } -bool Skeleton::is_using_bones_in_world_transform() const { - return use_bones_in_world_transform; + +Ref<SkinReference> Skeleton::register_skin(const Ref<Skin> &p_skin) { + + for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { + if (E->get()->skin == p_skin) { + return Ref<SkinReference>(E->get()); + } + } + + Ref<Skin> skin = p_skin; + + if (skin.is_null()) { + //need to create one from existing code, this is for compatibility only + //when skeletons did not support skins. It is also used by gizmo + //to display the skeleton. + + skin.instance(); + skin->set_bind_count(bones.size()); + _update_process_order(); //just in case + + // pose changed, rebuild cache of inverses + const Bone *bonesptr = bones.ptr(); + int len = bones.size(); + const int *order = process_order.ptr(); + + // calculate global rests and invert them + for (int i = 0; i < len; i++) { + const Bone &b = bonesptr[order[i]]; + if (b.parent >= 0) { + skin->set_bind_pose(order[i], skin->get_bind_pose(b.parent) * b.rest); + } else { + skin->set_bind_pose(order[i], b.rest); + } + } + + for (int i = 0; i < len; i++) { + //the inverse is what is actually required + skin->set_bind_bone(i, i); + skin->set_bind_pose(i, skin->get_bind_pose(i).affine_inverse()); + } + } + + ERR_FAIL_COND_V(skin.is_null(), Ref<SkinReference>()); + + Ref<SkinReference> skin_ref; + skin_ref.instance(); + + skin_ref->skeleton_node = this; + skin_ref->bind_count = 0; + skin_ref->skeleton = VisualServer::get_singleton()->skeleton_create(); + skin_ref->skeleton_node = this; + skin_ref->skin = skin; + + skin_bindings.insert(skin_ref.operator->()); + + skin->connect("changed", skin_ref.operator->(), "_skin_changed"); + return skin_ref; } void Skeleton::_bind_methods() { @@ -773,6 +789,8 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_rest", "bone_idx"), &Skeleton::get_bone_rest); ClassDB::bind_method(D_METHOD("set_bone_rest", "bone_idx", "rest"), &Skeleton::set_bone_rest); + ClassDB::bind_method(D_METHOD("register_skin", "skin"), &Skeleton::register_skin); + ClassDB::bind_method(D_METHOD("localize_rests"), &Skeleton::localize_rests); ClassDB::bind_method(D_METHOD("set_bone_disable_rest", "bone_idx", "disable"), &Skeleton::set_bone_disable_rest); @@ -787,17 +805,9 @@ void Skeleton::_bind_methods() { ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton::get_bone_pose); ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton::set_bone_pose); - ClassDB::bind_method(D_METHOD("set_bone_global_pose", "bone_idx", "pose"), &Skeleton::set_bone_global_pose); + ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton::set_bone_global_pose_override, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton::get_bone_global_pose); - ClassDB::bind_method(D_METHOD("get_bone_custom_pose", "bone_idx"), &Skeleton::get_bone_custom_pose); - ClassDB::bind_method(D_METHOD("set_bone_custom_pose", "bone_idx", "custom_pose"), &Skeleton::set_bone_custom_pose); - - ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform); - - ClassDB::bind_method(D_METHOD("set_use_bones_in_world_transform", "enable"), &Skeleton::set_use_bones_in_world_transform); - ClassDB::bind_method(D_METHOD("is_using_bones_in_world_transform"), &Skeleton::is_using_bones_in_world_transform); - #ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation); @@ -807,22 +817,19 @@ void Skeleton::_bind_methods() { #endif // _3D_DISABLED - ClassDB::bind_method(D_METHOD("set_bone_ignore_animation", "bone", "ignore"), &Skeleton::set_bone_ignore_animation); - - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones_in_world_transform"), "set_use_bones_in_world_transform", "is_using_bones_in_world_transform"); BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); } Skeleton::Skeleton() { - rest_global_inverse_dirty = true; dirty = false; process_order_dirty = true; - skeleton = VisualServer::get_singleton()->skeleton_create(); - set_notify_transform(true); - use_bones_in_world_transform = false; } Skeleton::~Skeleton() { - VisualServer::get_singleton()->free(skeleton); + + //some skins may remain bound + for (Set<SkinReference *>::Element *E = skin_bindings.front(); E; E = E->next()) { + E->get()->skeleton_node = nullptr; + } } diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 5b55dffbc8..f20c550055 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -33,6 +33,7 @@ #include "core/rid.h" #include "scene/3d/spatial.h" +#include "scene/resources/skin.h" #ifndef _3D_DISABLED typedef int BoneId; @@ -40,10 +41,38 @@ typedef int BoneId; class PhysicalBone; #endif // _3D_DISABLED +class Skeleton; + +class SkinReference : public Reference { + GDCLASS(SkinReference, Reference) + friend class Skeleton; + + Skeleton *skeleton_node; + RID skeleton; + Ref<Skin> skin; + uint32_t bind_count = 0; + void _skin_changed(); + +protected: + static void _bind_methods(); + +public: + RID get_skeleton() const; + Ref<Skin> get_skin() const; + ~SkinReference(); +}; + class Skeleton : public Spatial { GDCLASS(Skeleton, Spatial); +private: + friend class SkinReference; + + Set<SkinReference *> skin_bindings; + + void _skin_changed(); + struct Bone { String name; @@ -52,19 +81,15 @@ class Skeleton : public Spatial { int parent; int sort_index; //used for re-sorting process order - bool ignore_animation; - bool disable_rest; Transform rest; - Transform rest_global_inverse; Transform pose; Transform pose_global; - bool custom_pose_enable; - Transform custom_pose; - - Transform transform_final; + float global_pose_override_amount; + bool global_pose_override_reset; + Transform global_pose_override; #ifndef _3D_DISABLED PhysicalBone *physical_bone; @@ -76,9 +101,9 @@ class Skeleton : public Spatial { Bone() { parent = -1; enabled = true; - ignore_animation = false; - custom_pose_enable = false; disable_rest = false; + global_pose_override_amount = 0; + global_pose_override_reset = false; #ifndef _3D_DISABLED physical_bone = NULL; cache_parent_physical_bone = NULL; @@ -86,17 +111,12 @@ class Skeleton : public Spatial { } }; - bool rest_global_inverse_dirty; - Vector<Bone> bones; Vector<int> process_order; bool process_order_dirty; - RID skeleton; - void _make_dirty(); bool dirty; - bool use_bones_in_world_transform; // bind helpers Array _get_bound_child_nodes_to_bone(int p_bone) const { @@ -127,8 +147,6 @@ public: NOTIFICATION_UPDATE_SKELETON = 50 }; - RID get_skeleton() const; - // skeleton creation api void add_bone(const String &p_name); int find_bone(const String &p_name) const; @@ -141,9 +159,6 @@ public: void unparent_bone_and_rest(int p_bone); - void set_bone_ignore_animation(int p_bone, bool p_ignore); - bool is_bone_ignore_animation(int p_bone) const; - void set_bone_disable_rest(int p_bone, bool p_disable); bool is_bone_rest_disabled(int p_bone) const; @@ -151,10 +166,9 @@ public: void set_bone_rest(int p_bone, const Transform &p_rest); Transform get_bone_rest(int p_bone) const; - Transform get_bone_transform(int p_bone) const; Transform get_bone_global_pose(int p_bone) const; - void set_bone_global_pose(int p_bone, const Transform &p_pose); + void set_bone_global_pose_override(int p_bone, const Transform &p_pose, float p_amount, bool p_persistent = false); void set_bone_enabled(int p_bone, bool p_enabled); bool is_bone_enabled(int p_bone) const; @@ -170,14 +184,10 @@ public: void set_bone_pose(int p_bone, const Transform &p_pose); Transform get_bone_pose(int p_bone) const; - void set_bone_custom_pose(int p_bone, const Transform &p_custom_pose); - Transform get_bone_custom_pose(int p_bone) const; - void localize_rests(); // used for loaders and tools int get_process_order(int p_idx); - void set_use_bones_in_world_transform(bool p_enable); - bool is_using_bones_in_world_transform() const; + Ref<SkinReference> register_skin(const Ref<Skin> &p_skin); #ifndef _3D_DISABLED // Physical bone API diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 051f832882..728c23fbaa 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -256,7 +256,7 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) { Skeleton *sk = Object::cast_to<Skeleton>(child); bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0)); - if (bone_idx == -1 || sk->is_bone_ignore_animation(bone_idx)) { + if (bone_idx == -1) { continue; } diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index bb7c400cfe..eb152bc41e 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -622,7 +622,7 @@ bool AnimationTree::_update_caches(AnimationPlayer *player) { Skeleton *sk = Object::cast_to<Skeleton>(spatial); int bone_idx = sk->find_bone(path.get_subname(0)); - if (bone_idx != -1 && !sk->is_bone_ignore_animation(bone_idx)) { + if (bone_idx != -1) { track_xform->skeleton = sk; track_xform->bone_idx = bone_idx; diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 8f6d53c21c..ba5936562a 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -820,11 +820,7 @@ void AnimationTreePlayer::_process_animation(float p_delta) { t.value = t.object->get_indexed(t.subpath); t.value.zero(); - if (t.skeleton) { - t.skip = t.skeleton->is_bone_ignore_animation(t.bone_idx); - } else { - t.skip = false; - } + t.skip = false; } /* STEP 2 PROCESS ANIMATIONS */ diff --git a/scene/animation/skeleton_ik.cpp b/scene/animation/skeleton_ik.cpp index 7a1b10792b..4ec22cf3df 100644 --- a/scene/animation/skeleton_ik.cpp +++ b/scene/animation/skeleton_ik.cpp @@ -320,7 +320,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove new_bone_pose.basis = new_bone_pose.basis * p_task->chain.tips[0].end_effector->goal_transform.basis; } - p_task->skeleton->set_bone_global_pose(ci->bone, new_bone_pose); + p_task->skeleton->set_bone_global_pose_override(ci->bone, new_bone_pose, 1.0); if (!ci->children.empty()) ci = &ci->children.write[0]; diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 0f7d4466c8..1f9793190d 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -191,7 +191,7 @@ void Tween::_notification(int p_what) { case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { // Are we processing during 'regular' time? if (tween_process_mode == TWEEN_PROCESS_IDLE) - // Do nothing since we whould only process during idle time + // Do nothing since we would only process during idle time break; // Should we update? diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 174c2fce7d..d39f017cad 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -818,7 +818,7 @@ Size2 Control::get_minimum_size() const { Ref<Texture> Control::get_icon(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const Ref<Texture> *tex = data.icon_override.getptr(p_name); if (tex) @@ -860,7 +860,7 @@ Ref<Texture> Control::get_icon(const StringName &p_name, const StringName &p_typ } Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const Ref<Shader> *sdr = data.shader_override.getptr(p_name); if (sdr) @@ -903,7 +903,7 @@ Ref<Shader> Control::get_shader(const StringName &p_name, const StringName &p_ty Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const Ref<StyleBox> *style = data.style_override.getptr(p_name); if (style) return *style; @@ -949,7 +949,7 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName & } Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const Ref<Font> *font = data.font_override.getptr(p_name); if (font) return *font; @@ -986,7 +986,7 @@ Ref<Font> Control::get_font(const StringName &p_name, const StringName &p_type) } Color Control::get_color(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const Color *color = data.color_override.getptr(p_name); if (color) return *color; @@ -1026,7 +1026,7 @@ Color Control::get_color(const StringName &p_name, const StringName &p_type) con int Control::get_constant(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { const int *constant = data.constant_override.getptr(p_name); if (constant) return *constant; @@ -1102,7 +1102,7 @@ bool Control::has_constant_override(const StringName &p_name) const { bool Control::has_icon(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_icon_override(p_name)) return true; } @@ -1141,7 +1141,7 @@ bool Control::has_icon(const StringName &p_name, const StringName &p_type) const bool Control::has_shader(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_shader_override(p_name)) return true; } @@ -1179,7 +1179,7 @@ bool Control::has_shader(const StringName &p_name, const StringName &p_type) con } bool Control::has_stylebox(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_stylebox_override(p_name)) return true; } @@ -1217,7 +1217,7 @@ bool Control::has_stylebox(const StringName &p_name, const StringName &p_type) c } bool Control::has_font(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_font_override(p_name)) return true; } @@ -1256,7 +1256,7 @@ bool Control::has_font(const StringName &p_name, const StringName &p_type) const bool Control::has_color(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_color_override(p_name)) return true; } @@ -1295,7 +1295,7 @@ bool Control::has_color(const StringName &p_name, const StringName &p_type) cons bool Control::has_constant(const StringName &p_name, const StringName &p_type) const { - if (p_type == StringName() || p_type == "") { + if (p_type == StringName() || p_type == get_class_name()) { if (has_constant_override(p_name)) return true; } diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 59bbdad97a..9ed1d2bf45 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -35,6 +35,7 @@ #ifdef TOOLS_ENABLED #include "editor/editor_node.h" +#include "scene/main/viewport.h" // Only used to check for more modals when dimming the editor. #endif // WindowDialog @@ -59,7 +60,7 @@ void WindowDialog::_fix_size() { float left = 0; float bottom = 0; float right = 0; - // Check validity, because the theme could contain a different type of StyleBox + // Check validity, because the theme could contain a different type of StyleBox. if (panel->get_class() == "StyleBoxTexture") { Ref<StyleBoxTexture> panel_texture = Object::cast_to<StyleBoxTexture>(*panel); top = panel_texture->get_expand_margin_size(MARGIN_TOP); @@ -242,7 +243,7 @@ void WindowDialog::_notification(int p_what) { } break; case NOTIFICATION_POPUP_HIDE: { - if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton()) + if (get_tree() && Engine::get_singleton()->is_editor_hint() && EditorNode::get_singleton() && !get_viewport()->gui_has_modal_stack()) EditorNode::get_singleton()->dim_editor(false); } break; #endif diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 2445456a1f..04e03f569e 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -201,7 +201,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { switch (code) { - case (KEY_X): { // CUT + case (KEY_X): { // CUT. if (editable) { cut_text(); @@ -209,12 +209,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; - case (KEY_C): { // COPY + case (KEY_C): { // COPY. + copy_text(); } break; - case (KEY_V): { // PASTE + case (KEY_V): { // PASTE. if (editable) { @@ -223,7 +224,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; - case (KEY_Z): { // undo / redo + case (KEY_Z): { // Undo/redo. if (editable) { if (k->get_shift()) { redo(); @@ -233,7 +234,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } } break; - case (KEY_U): { // Delete from start to cursor + case (KEY_U): { // Delete from start to cursor. if (editable) { @@ -254,7 +255,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; - case (KEY_Y): { // PASTE (Yank for unix users) + case (KEY_Y): { // PASTE (Yank for unix users). if (editable) { @@ -262,7 +263,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } } break; - case (KEY_K): { // Delete from cursor_pos to end + case (KEY_K): { // Delete from cursor_pos to end. if (editable) { @@ -272,15 +273,15 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } } break; - case (KEY_A): { //Select All + case (KEY_A): { // Select all. select(); } break; #ifdef APPLE_STYLE_KEYS - case (KEY_LEFT): { // Go to start of text - like HOME key + case (KEY_LEFT): { // Go to start of text - like HOME key. set_cursor_position(0); } break; - case (KEY_RIGHT): { // Go to end of text - like END key + case (KEY_RIGHT): { // Go to end of text - like END key. set_cursor_position(text.length()); } break; #endif @@ -473,7 +474,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { int text_len = text.length(); if (cursor_pos == text_len) - break; // nothing to do + break; // Nothing to do. #ifdef APPLE_STYLE_KEYS if (k->get_alt()) { @@ -531,6 +532,16 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { set_cursor_position(text.length()); shift_selection_check_post(k->get_shift()); } break; + case KEY_MENU: { + if (context_menu_enabled) { + Point2 pos = Point2(get_cursor_pixel_pos(), (get_size().y + get_font("font")->get_height()) / 2); + menu->set_position(get_global_transform().xform(pos)); + menu->set_size(Vector2(1, 1)); + menu->set_scale(get_global_transform().get_scale()); + menu->popup(); + menu->grab_focus(); + } + } break; default: { @@ -730,7 +741,7 @@ void LineEdit::_notification(int p_what) { Color cursor_color = get_color("cursor_color"); const String &t = using_placeholder ? placeholder_translated : text; - // draw placeholder color + // Draw placeholder color. if (using_placeholder) font_color.a *= placeholder_alpha; @@ -745,24 +756,28 @@ void LineEdit::_notification(int p_what) { color_icon = get_color("clear_button_color"); } } - r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); + + float icon_width = MIN(r_icon->get_width(), r_icon->get_width() * (height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))) / r_icon->get_height()); + float icon_height = MIN(r_icon->get_height(), height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))); + Rect2 icon_region = Rect2(Point2(width - icon_width - style->get_margin(MARGIN_RIGHT), height / 2 - icon_height / 2), Size2(icon_width, icon_height)); + draw_texture_rect_region(r_icon, icon_region, Rect2(Point2(), r_icon->get_size()), color_icon); if (align == ALIGN_CENTER) { if (window_pos == 0) { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2); + x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - cached_text_width - icon_width - style->get_margin(MARGIN_RIGHT) * 2) / 2); } } else { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT)); + x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - icon_width - style->get_margin(MARGIN_RIGHT)); } - ofs_max -= r_icon->get_width(); + ofs_max -= icon_width; } int caret_height = font->get_height() > y_area ? y_area : font->get_height(); FontDrawer drawer(font, Color(1, 1, 1)); while (true) { - //end of string, break! + // End of string, break. if (char_ofs >= t.length()) break; @@ -799,7 +814,7 @@ void LineEdit::_notification(int p_what) { CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1]; int char_width = font->get_char_size(cchar, next).width; - // end of widget, break! + // End of widget, break. if ((x_ofs + char_width) > ofs_max) break; @@ -854,7 +869,7 @@ void LineEdit::_notification(int p_what) { } } - if (char_ofs == cursor_pos && draw_caret) { //may be at the end + if (char_ofs == cursor_pos && draw_caret) { // May be at the end. if (ime_text.length() == 0) { #ifdef TOOLS_ENABLED VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(Math::round(EDSCALE), caret_height)), cursor_color); @@ -1043,7 +1058,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { } pixel_ofs += char_w; - if (pixel_ofs > p_x) { //found what we look for + if (pixel_ofs > p_x) { // Found what we look for. break; } @@ -1053,6 +1068,52 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { set_cursor_position(ofs); } +int LineEdit::get_cursor_pixel_pos() { + + Ref<Font> font = get_font("font"); + int ofs = window_pos; + Ref<StyleBox> style = get_stylebox("normal"); + int pixel_ofs = 0; + Size2 size = get_size(); + bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; + int r_icon_width = Control::get_icon("clear")->get_width(); + + switch (align) { + + case ALIGN_FILL: + case ALIGN_LEFT: { + + pixel_ofs = int(style->get_offset().x); + } break; + case ALIGN_CENTER: { + + if (window_pos != 0) + pixel_ofs = int(style->get_offset().x); + else + pixel_ofs = int(size.width - (cached_width)) / 2; + + if (display_clear_icon) + pixel_ofs -= int(r_icon_width / 2 + style->get_margin(MARGIN_RIGHT)); + } break; + case ALIGN_RIGHT: { + + pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width)); + + if (display_clear_icon) + pixel_ofs -= int(r_icon_width + style->get_margin(MARGIN_RIGHT)); + } break; + } + + while (ofs < cursor_pos) { + if (font != NULL) { + pixel_ofs += font->get_char_size(text[ofs]).width; + } + ofs++; + } + + return pixel_ofs; +} + bool LineEdit::cursor_get_blink_enabled() const { return caret_blink_enabled; } @@ -1210,15 +1271,18 @@ void LineEdit::set_cursor_position(int p_pos) { Ref<Font> font = get_font("font"); if (cursor_pos <= window_pos) { - /* Adjust window if cursor goes too much to the left */ + // Adjust window if cursor goes too much to the left. set_window_pos(MAX(0, cursor_pos - 1)); } else { - /* Adjust window if cursor goes too much to the right */ + // Adjust window if cursor goes too much to the right. int window_width = get_size().width - style->get_minimum_size().width; bool display_clear_icon = !text.empty() && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref<Texture> r_icon = display_clear_icon ? Control::get_icon("clear") : right_icon; - window_width -= r_icon->get_width(); + + float icon_width = MIN(r_icon->get_width(), r_icon->get_width() * (get_size().height - (style->get_margin(MARGIN_TOP) + style->get_margin(MARGIN_BOTTOM))) / r_icon->get_height()); + + window_width -= icon_width; } if (window_width < 0) @@ -1232,10 +1296,10 @@ void LineEdit::set_cursor_position(int p_pos) { for (int i = cursor_pos; i >= window_pos; i--) { if (i >= text.length()) { - //do not do this, because if the cursor is at the end, its just fine that it takes no space - //accum_width = font->get_char_size(' ').width; //anything should do + // Do not do this, because if the cursor is at the end, its just fine that it takes no space. + // accum_width = font->get_char_size(' ').width; } else { - accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; //anything should do + accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; // Anything should do. } if (accum_width > window_width) break; @@ -1300,12 +1364,13 @@ Size2 LineEdit::get_minimum_size() const { Size2 min = style->get_minimum_size(); min.height += font->get_height(); - //minimum size of text + // Minimum size of text. int space_size = font->get_char_size(' ').x; int mstext = get_constant("minimum_spaces") * space_size; if (expand_to_text_length) { - mstext = MAX(mstext, font->get_string_size(text).x + space_size); //add a spce because some fonts are too exact, and because cursor needs a bit more when at the end + // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end. + mstext = MAX(mstext, font->get_string_size(text).x + space_size); } min.width += mstext; @@ -1313,8 +1378,6 @@ Size2 LineEdit::get_minimum_size() const { return min; } -/* selection */ - void LineEdit::deselect() { selection.begin = 0; @@ -1404,8 +1467,8 @@ bool LineEdit::is_secret() const { void LineEdit::set_secret_character(const String &p_string) { - // An empty string as the secret character would crash the engine - // It also wouldn't make sense to use multiple characters as the secret character + // An empty string as the secret character would crash the engine. + // It also wouldn't make sense to use multiple characters as the secret character. ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)."); secret_character = p_string; @@ -1557,8 +1620,11 @@ void LineEdit::set_right_icon(const Ref<Texture> &p_icon) { update(); } -void LineEdit::_text_changed() { +Ref<Texture> LineEdit::get_right_icon() { + return right_icon; +} +void LineEdit::_text_changed() { if (expand_to_text_length) minimum_size_changed(); @@ -1679,6 +1745,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled"), &LineEdit::is_shortcut_keys_enabled); ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &LineEdit::set_selecting_enabled); ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &LineEdit::is_selecting_enabled); + ClassDB::bind_method(D_METHOD("set_right_icon", "icon"), &LineEdit::set_right_icon); + ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon); ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text"))); ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text"))); @@ -1709,6 +1777,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon"); ADD_GROUP("Placeholder", "placeholder_"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); ADD_PROPERTY(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha"); @@ -1755,7 +1824,7 @@ LineEdit::LineEdit() { context_menu_enabled = true; menu = memnew(PopupMenu); add_child(menu); - editable = false; // initialise to opposite first, so we get past the early-out in set_editable + editable = false; // Initialise to opposite first, so we get past the early-out in set_editable. set_editable(true); menu->connect("id_pressed", this, "menu_option"); expand_to_text_length = false; diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index c8fe845e3e..3424131dad 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -82,7 +82,7 @@ private: int cursor_pos; int window_pos; - int max_length; // 0 for no maximum + int max_length; // 0 for no maximum. int cached_width; int cached_placeholder_width; @@ -143,6 +143,7 @@ private: void set_window_pos(int p_pos); void set_cursor_at_pixel_pos(int p_x); + int get_cursor_pixel_pos(); void _reset_caret_blink_timer(); void _toggle_draw_caret(); @@ -229,6 +230,7 @@ public: bool is_selecting_enabled() const; void set_right_icon(const Ref<Texture> &p_icon); + Ref<Texture> get_right_icon(); virtual bool is_text_field() const; LineEdit(); diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index d1840e43a3..de8df4215d 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -116,10 +116,16 @@ void OptionButton::add_item(const String &p_label, int p_id) { void OptionButton::set_item_text(int p_idx, const String &p_text) { popup->set_item_text(p_idx, p_text); + + if (current == p_idx) + set_text(p_text); } void OptionButton::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { popup->set_item_icon(p_idx, p_icon); + + if (current == p_idx) + set_icon(p_icon); } void OptionButton::set_item_id(int p_idx, int p_id) { diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h index 6755f9ef2a..1c212700ef 100644 --- a/scene/gui/rich_text_label.h +++ b/scene/gui/rich_text_label.h @@ -456,7 +456,7 @@ public: void push_meta(const Variant &p_meta); void push_table(int p_columns); void push_fade(int p_start_index, int p_length); - void push_shake(int p_level, float p_rate); + void push_shake(int p_strength, float p_rate); void push_wave(float p_frequency, float p_amplitude); void push_tornado(float p_frequency, float p_radius); void push_rainbow(float p_saturation, float p_value, float p_frequency); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 5173b83407..d5f1d317c7 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -647,7 +647,7 @@ void TextEdit::_notification(int p_what) { if (scrolling && get_v_scroll() != target_v_scroll) { double target_y = target_v_scroll - get_v_scroll(); double dist = sqrt(target_y * target_y); - // To ensure minimap is responsive overide the speed setting. + // To ensure minimap is responsive override the speed setting. double vel = ((target_y / dist) * ((minimap_clicked) ? 3000 : v_scroll_speed)) * get_physics_process_delta_time(); if (Math::abs(vel) >= dist) { @@ -2081,6 +2081,44 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co r_col = col; } +Vector2i TextEdit::_get_cursor_pixel_pos() { + adjust_viewport_to_cursor(); + int row = (cursor.line - get_first_visible_line() - cursor.wrap_ofs); + // Correct for hidden and wrapped lines + for (int i = get_first_visible_line(); i < cursor.line; i++) { + if (is_line_hidden(i)) { + row -= 1; + continue; + } + row += times_line_wraps(i); + } + // Row might be wrapped. Adjust row and r_column + Vector<String> rows2 = get_wrap_rows_text(cursor.line); + while (rows2.size() > 1) { + if (cursor.column >= rows2[0].length()) { + cursor.column -= rows2[0].length(); + rows2.remove(0); + row++; + } else { + break; + } + } + + // Calculate final pixel position + int y = (row - get_v_scroll_offset() + 1 /*Bottom of line*/) * get_row_height(); + int x = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width - cursor.x_ofs; + int ix = 0; + while (ix < rows2[0].size() && ix < cursor.column) { + if (cache.font != NULL) { + x += cache.font->get_char_size(rows2[0].get(ix)).width; + } + ix++; + } + x += get_indent_level(cursor.line) * cache.font->get_char_size(' ').width; + + return Vector2i(x, y); +} + void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const { float rows = p_mouse.y; @@ -2417,7 +2455,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (mm.is_valid()) { if (select_identifiers_enabled) { - if (mm->get_command() && mm->get_button_mask() == 0) { + if (!dragging_minimap && !dragging_selection && mm->get_command() && mm->get_button_mask() == 0) { String new_word = get_word_at_pos(mm->get_position()); if (new_word != highlighted_word) { @@ -2475,7 +2513,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { #endif if (select_identifiers_enabled) { - if (k->is_pressed()) { + if (k->is_pressed() && !dragging_minimap && !dragging_selection) { highlighted_word = get_word_at_pos(get_local_mouse_position()); update(); @@ -3596,6 +3634,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } break; + case KEY_MENU: { + if (context_menu_enabled) { + menu->set_position(get_global_transform().xform(_get_cursor_pixel_pos())); + menu->set_size(Vector2(1, 1)); + menu->set_scale(get_global_transform().get_scale()); + menu->popup(); + menu->grab_focus(); + } + } break; + default: { scancode_handled = false; @@ -6282,7 +6330,7 @@ void TextEdit::_confirm_completion() { CharType last_completion_char = completion_current.insert_text[completion_current.insert_text.length() - 1]; if ((last_completion_char == '"' || last_completion_char == '\'') && last_completion_char == next_char) { - _base_remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); + _remove_text(cursor.line, cursor.column, cursor.line, cursor.column + 1); } if (last_completion_char == '(') { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index e98201c1eb..e5d9b006fe 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -587,6 +587,7 @@ public: int cursor_get_column() const; int cursor_get_line() const; + Vector2i _get_cursor_pixel_pos(); bool cursor_get_blink_enabled() const; void cursor_set_blink_enabled(const bool p_enabled); diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 2a18436a5e..57663bbe82 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -328,7 +328,7 @@ void TreeItem::set_collapsed(bool p_collapsed) { ci = ci->parent; } - if (ci) { // collapsing cursor/selectd, move it! + if (ci) { // collapsing cursor/selected, move it! if (tree->select_mode == Tree::SELECT_MULTI) { @@ -914,7 +914,6 @@ void Tree::update_cache() { cache.arrow_collapsed = get_icon("arrow_collapsed"); cache.arrow = get_icon("arrow"); cache.select_arrow = get_icon("select_arrow"); - cache.select_option = get_icon("select_option"); cache.updown = get_icon("updown"); cache.custom_button = get_stylebox("custom_button"); @@ -930,7 +929,6 @@ void Tree::update_cache() { cache.vseparation = get_constant("vseparation"); cache.item_margin = get_constant("item_margin"); cache.button_margin = get_constant("button_margin"); - cache.guide_width = get_constant("guide_width"); cache.draw_guides = get_constant("draw_guides"); cache.draw_relationship_lines = get_constant("draw_relationship_lines"); cache.relationship_line_color = get_color("relationship_line_color"); diff --git a/scene/gui/tree.h b/scene/gui/tree.h index fdc6da5055..f12d8fc4d2 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -416,7 +416,6 @@ private: Ref<Texture> arrow_collapsed; Ref<Texture> arrow; Ref<Texture> select_arrow; - Ref<Texture> select_option; Ref<Texture> updown; Color font_color; @@ -429,7 +428,6 @@ private: int hseparation; int vseparation; int item_margin; - int guide_width; int button_margin; Point2 offset; int draw_relationship_lines; diff --git a/scene/main/node.cpp b/scene/main/node.cpp index bd01ca2886..ba04cb69f2 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -2861,6 +2861,8 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_WM_ABOUT); BIND_CONSTANT(NOTIFICATION_CRASH); BIND_CONSTANT(NOTIFICATION_OS_IME_UPDATE); + BIND_CONSTANT(NOTIFICATION_APP_RESUMED); + BIND_CONSTANT(NOTIFICATION_APP_PAUSED); BIND_ENUM_CONSTANT(PAUSE_MODE_INHERIT); BIND_ENUM_CONSTANT(PAUSE_MODE_STOP); diff --git a/scene/main/node.h b/scene/main/node.h index 51a1436014..a8bcd2f273 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -250,7 +250,9 @@ public: 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 + NOTIFICATION_OS_IME_UPDATE = MainLoop::NOTIFICATION_OS_IME_UPDATE, + NOTIFICATION_APP_RESUMED = MainLoop::NOTIFICATION_APP_RESUMED, + NOTIFICATION_APP_PAUSED = MainLoop::NOTIFICATION_APP_PAUSED }; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 5483fe1d6f..0465c9305b 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -630,6 +630,7 @@ void SceneTree::_notification(int p_notification) { break; } } break; + case NOTIFICATION_WM_GO_BACK_REQUEST: { get_root()->propagate_notification(p_notification); @@ -639,28 +640,23 @@ void SceneTree::_notification(int p_notification) { break; } } break; - case NOTIFICATION_OS_MEMORY_WARNING: - case NOTIFICATION_OS_IME_UPDATE: - case NOTIFICATION_WM_MOUSE_ENTER: - case NOTIFICATION_WM_MOUSE_EXIT: - case NOTIFICATION_WM_FOCUS_IN: - case NOTIFICATION_WM_FOCUS_OUT: - case NOTIFICATION_WM_ABOUT: { - if (p_notification == NOTIFICATION_WM_FOCUS_IN) { - InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); - if (id) { - id->ensure_touch_mouse_raised(); - } + case NOTIFICATION_WM_FOCUS_IN: { + + InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton()); + if (id) { + id->ensure_touch_mouse_raised(); } get_root()->propagate_notification(p_notification); } break; + case NOTIFICATION_TRANSLATION_CHANGED: { if (!Engine::get_singleton()->is_editor_hint()) { 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); @@ -669,7 +665,15 @@ void SceneTree::_notification(int p_notification) { } break; - case NOTIFICATION_CRASH: { + case NOTIFICATION_OS_MEMORY_WARNING: + case NOTIFICATION_OS_IME_UPDATE: + case NOTIFICATION_WM_MOUSE_ENTER: + case NOTIFICATION_WM_MOUSE_EXIT: + case NOTIFICATION_WM_FOCUS_OUT: + case NOTIFICATION_WM_ABOUT: + case NOTIFICATION_CRASH: + case NOTIFICATION_APP_RESUMED: + case NOTIFICATION_APP_PAUSED: { get_root()->propagate_notification(p_notification); } break; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index e3af521e8c..418ee6af0e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -364,6 +364,9 @@ void register_scene_types() { /* REGISTER 3D */ + ClassDB::register_class<Skin>(); + ClassDB::register_virtual_class<SkinReference>(); + ClassDB::register_class<Spatial>(); ClassDB::register_virtual_class<SpatialGizmo>(); ClassDB::register_class<Skeleton>(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index d761eb01fe..f68dc9af38 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -657,7 +657,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_constant("hseparation", "Tree", 4 * scale); theme->set_constant("vseparation", "Tree", 4 * scale); - theme->set_constant("guide_width", "Tree", 2 * scale); theme->set_constant("item_margin", "Tree", 12 * scale); theme->set_constant("button_margin", "Tree", 4 * scale); theme->set_constant("draw_relationship_lines", "Tree", 0); diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp index cd229732ba..1c41f30a94 100644 --- a/scene/resources/resource_format_text.cpp +++ b/scene/resources/resource_format_text.cpp @@ -1713,6 +1713,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r } if (groups.size()) { + groups.sort_custom<StringName::AlphCompare>(); String sgroups = " groups=[\n"; for (int j = 0; j < groups.size(); j++) { sgroups += "\"" + String(groups[j]).c_escape() + "\",\n"; diff --git a/scene/resources/skin.cpp b/scene/resources/skin.cpp new file mode 100644 index 0000000000..8446e2f249 --- /dev/null +++ b/scene/resources/skin.cpp @@ -0,0 +1,102 @@ +#include "skin.h" + +void Skin::set_bind_count(int p_size) { + ERR_FAIL_COND(p_size < 0); + binds.resize(p_size); + binds_ptr = binds.ptrw(); + bind_count = p_size; + emit_changed(); +} + +void Skin::add_bind(int p_bone, const Transform &p_pose) { + uint32_t index = bind_count; + set_bind_count(bind_count + 1); + set_bind_bone(index, p_bone); + set_bind_pose(index, p_pose); +} + +void Skin::set_bind_bone(int p_index, int p_bone) { + ERR_FAIL_INDEX(p_index, bind_count); + binds_ptr[p_index].bone = p_bone; + emit_changed(); +} + +void Skin::set_bind_pose(int p_index, const Transform &p_pose) { + ERR_FAIL_INDEX(p_index, bind_count); + binds_ptr[p_index].pose = p_pose; + emit_changed(); +} + +void Skin::clear_binds() { + binds.clear(); + binds_ptr = nullptr; + bind_count = 0; + emit_changed(); +} + +bool Skin::_set(const StringName &p_name, const Variant &p_value) { + String name = p_name; + if (name == "bind_count") { + set_bind_count(p_value); + return true; + } else if (name.begins_with("bind/")) { + int index = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + if (what == "bone") { + set_bind_bone(index, p_value); + return true; + } else if (what == "pose") { + set_bind_pose(index, p_value); + return true; + } + } + return false; +} + +bool Skin::_get(const StringName &p_name, Variant &r_ret) const { + + String name = p_name; + if (name == "bind_count") { + r_ret = get_bind_count(); + return true; + } else if (name.begins_with("bind/")) { + int index = name.get_slicec('/', 1).to_int(); + String what = name.get_slicec('/', 2); + if (what == "bone") { + r_ret = get_bind_bone(index); + return true; + } else if (what == "pose") { + r_ret = get_bind_pose(index); + return true; + } + } + return false; +} +void Skin::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::INT, "bind_count", PROPERTY_HINT_RANGE, "0,16384,1,or_greater")); + for (int i = 0; i < get_bind_count(); i++) { + p_list->push_back(PropertyInfo(Variant::INT, "bind/" + itos(i) + "/bone", PROPERTY_HINT_RANGE, "0,16384,1,or_greater")); + p_list->push_back(PropertyInfo(Variant::TRANSFORM, "bind/" + itos(i) + "/pose")); + } +} + +void Skin::_bind_methods() { + + ClassDB::bind_method(D_METHOD("set_bind_count", "bind_count"), &Skin::set_bind_count); + ClassDB::bind_method(D_METHOD("get_bind_count"), &Skin::get_bind_count); + + ClassDB::bind_method(D_METHOD("add_bind", "bone", "pose"), &Skin::add_bind); + + ClassDB::bind_method(D_METHOD("set_bind_pose", "bind_index", "pose"), &Skin::set_bind_pose); + ClassDB::bind_method(D_METHOD("get_bind_pose", "bind_index"), &Skin::get_bind_pose); + + ClassDB::bind_method(D_METHOD("set_bind_bone", "bind_index", "bone"), &Skin::set_bind_bone); + ClassDB::bind_method(D_METHOD("get_bind_bone", "bind_index"), &Skin::get_bind_bone); + + ClassDB::bind_method(D_METHOD("clear_binds"), &Skin::clear_binds); +} + +Skin::Skin() { + bind_count = 0; + binds_ptr = nullptr; +} diff --git a/scene/resources/skin.h b/scene/resources/skin.h new file mode 100644 index 0000000000..a7e55bfa89 --- /dev/null +++ b/scene/resources/skin.h @@ -0,0 +1,54 @@ +#ifndef SKIN_H +#define SKIN_H + +#include "core/resource.h" + +class Skin : public Resource { + GDCLASS(Skin, Resource) + + struct Bind { + int bone; + Transform pose; + }; + + Vector<Bind> binds; + + Bind *binds_ptr; + int bind_count; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + static void _bind_methods(); + +public: + void set_bind_count(int p_size); + inline int get_bind_count() const { return bind_count; } + + void add_bind(int p_bone, const Transform &p_pose); + + void set_bind_bone(int p_index, int p_bone); + void set_bind_pose(int p_index, const Transform &p_pose); + + inline int get_bind_bone(int p_index) const { +#ifdef DEBUG_ENABLED + ERR_FAIL_INDEX_V(p_index, bind_count, -1); +#endif + return binds_ptr[p_index].bone; + } + + inline Transform get_bind_pose(int p_index) const { +#ifdef DEBUG_ENABLED + ERR_FAIL_INDEX_V(p_index, bind_count, Transform()); +#endif + return binds_ptr[p_index].pose; + } + + void clear_binds(); + + Skin(); +}; + +#endif // SKIN_H |