diff options
Diffstat (limited to 'scene/3d/skeleton_3d.cpp')
-rw-r--r-- | scene/3d/skeleton_3d.cpp | 593 |
1 files changed, 341 insertions, 252 deletions
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp index f0ffb7b2d5..566801c9f7 100644 --- a/scene/3d/skeleton_3d.cpp +++ b/scene/3d/skeleton_3d.cpp @@ -32,10 +32,11 @@ #include "skeleton_3d.compat.inc" #include "core/variant/type_info.h" -#include "scene/3d/physics/physical_bone_3d.h" -#include "scene/3d/physics/physics_body_3d.h" #include "scene/resources/surface_tool.h" #include "scene/scene_string_names.h" +#ifndef DISABLE_DEPRECATED +#include "scene/3d/physical_bone_simulator_3d.h" +#endif // _DISABLE_DEPRECATED void SkinReference::_skin_changed() { if (skeleton_node) { @@ -70,6 +71,12 @@ SkinReference::~SkinReference() { bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { String path = p_path; +#ifndef DISABLE_DEPRECATED + if (path.begins_with("animate_physical_bones")) { + set_animate_physical_bones(p_value); + } +#endif + if (!path.begins_with("bones/")) { return false; } @@ -134,6 +141,12 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) { bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const { String path = p_path; +#ifndef DISABLE_DEPRECATED + if (path.begins_with("animate_physical_bones")) { + r_ret = get_animate_physical_bones(); + } +#endif + if (!path.begins_with("bones/")) { return false; } @@ -251,26 +264,70 @@ void Skeleton3D::_update_process_order() { } process_order_dirty = false; + + emit_signal("bone_list_changed"); } +#ifndef DISABLE_DEPRECATED +void Skeleton3D::setup_simulator() { + PhysicalBoneSimulator3D *sim = memnew(PhysicalBoneSimulator3D); + simulator = sim; + sim->is_compat = true; + sim->set_active(false); // Don't run unneeded process. + add_child(sim); +} + +void Skeleton3D::remove_simulator() { + remove_child(simulator); + memdelete(simulator); +} +#endif // _DISABLE_DEPRECATED + void Skeleton3D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { - if (dirty) { - notification(NOTIFICATION_UPDATE_SKELETON); - } + _process_changed(); + _make_modifiers_dirty(); + force_update_all_dirty_bones(); +#ifndef DISABLE_DEPRECATED + setup_simulator(); +#endif // _DISABLE_DEPRECATED + } break; +#ifndef DISABLE_DEPRECATED + case NOTIFICATION_EXIT_TREE: { + remove_simulator(); } break; +#endif // _DISABLE_DEPRECATED case NOTIFICATION_UPDATE_SKELETON: { - RenderingServer *rs = RenderingServer::get_singleton(); - Bone *bonesptr = bones.ptrw(); + // Update bone transforms to apply unprocessed poses. + force_update_all_dirty_bones(); + + updating = true; + Bone *bonesptr = bones.ptrw(); int len = bones.size(); - dirty = false; - // Update bone transforms. - force_update_all_bone_transforms(); + // Process modifiers. + _find_modifiers(); + LocalVector<Transform3D> current_bone_poses; + LocalVector<Vector3> current_pose_positions; + LocalVector<Quaternion> current_pose_rotations; + LocalVector<Vector3> current_pose_scales; + LocalVector<Transform3D> current_bone_global_poses; + if (!modifiers.is_empty()) { + // Store unmodified bone poses. + for (int i = 0; i < len; i++) { + current_bone_poses.push_back(bones[i].pose_cache); + current_pose_positions.push_back(bones[i].pose_position); + current_pose_rotations.push_back(bones[i].pose_rotation); + current_pose_scales.push_back(bones[i].pose_scale); + current_bone_global_poses.push_back(bones[i].global_pose); + } + _process_modifiers(); + } // Update skins. + RenderingServer *rs = RenderingServer::get_singleton(); for (SkinReference *E : skin_bindings) { const Skin *skin = E->skin.operator->(); RID skeleton = E->skeleton; @@ -322,74 +379,78 @@ void Skeleton3D::_notification(int p_what) { for (uint32_t i = 0; i < bind_count; i++) { uint32_t bone_index = E->skin_bone_indices_ptrs[i]; ERR_CONTINUE(bone_index >= (uint32_t)len); - rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].pose_global * skin->get_bind_pose(i)); + rs->skeleton_bone_set_transform(skeleton, i, bonesptr[bone_index].global_pose * skin->get_bind_pose(i)); } } - emit_signal(SceneStringNames::get_singleton()->pose_updated); - } break; -#ifndef _3D_DISABLED - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { - // This is active only if the skeleton animates the physical bones - // and the state of the bone is not active. - if (animate_physical_bones) { - for (int i = 0; i < bones.size(); i += 1) { - if (bones[i].physical_bone) { - if (bones[i].physical_bone->is_simulating_physics() == false) { - bones[i].physical_bone->reset_to_rest_position(); - } - } + if (!modifiers.is_empty()) { + // Restore unmodified bone poses. + for (int i = 0; i < len; i++) { + bonesptr[i].pose_cache = current_bone_poses[i]; + bonesptr[i].pose_position = current_pose_positions[i]; + bonesptr[i].pose_rotation = current_pose_rotations[i]; + bonesptr[i].pose_scale = current_pose_scales[i]; + bonesptr[i].global_pose = current_bone_global_poses[i]; } } + + updating = false; + is_update_needed = false; } break; - case NOTIFICATION_READY: { - if (Engine::get_singleton()->is_editor_hint()) { - set_physics_process_internal(true); + case NOTIFICATION_INTERNAL_PROCESS: + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + _find_modifiers(); + if (!modifiers.is_empty()) { + _update_deferred(); } } break; -#endif // _3D_DISABLED } } -void Skeleton3D::clear_bones_global_pose_override() { - for (int i = 0; i < bones.size(); i += 1) { - bones.write[i].global_pose_override_amount = 0; - bones.write[i].global_pose_override_reset = true; +void Skeleton3D::set_modifier_callback_mode_process(Skeleton3D::ModifierCallbackModeProcess p_mode) { + if (modifier_callback_mode_process == p_mode) { + return; } - _make_dirty(); + modifier_callback_mode_process = p_mode; + _process_changed(); } -void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - 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(); +Skeleton3D::ModifierCallbackModeProcess Skeleton3D::get_modifier_callback_mode_process() const { + return modifier_callback_mode_process; } -Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - return bones[p_bone].global_pose_override; +void Skeleton3D::_process_changed() { + if (modifier_callback_mode_process == MODIFIER_CALLBACK_MODE_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else if (modifier_callback_mode_process == MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS) { + set_process_internal(false); + set_physics_process_internal(true); + } +} + +void Skeleton3D::_make_modifiers_dirty() { + modifiers_dirty = true; + _update_deferred(); } Transform3D Skeleton3D::get_bone_global_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); - } - return bones[p_bone].pose_global; + const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones(); + return bones[p_bone].global_pose; } -Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { +void Skeleton3D::set_bone_global_pose(int p_bone, const Transform3D &p_pose) { const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + ERR_FAIL_INDEX(p_bone, bone_size); + + Transform3D pt; + if (bones[p_bone].parent >= 0) { + pt = get_bone_global_pose(bones[p_bone].parent); } - return bones[p_bone].pose_global_no_override; + Transform3D t = pt.affine_inverse() * p_pose; + set_bone_pose(p_bone, t); } void Skeleton3D::set_motion_scale(float p_motion_scale) { @@ -548,7 +609,7 @@ Transform3D Skeleton3D::get_bone_global_rest(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); if (rest_dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + const_cast<Skeleton3D *>(this)->force_update_all_bone_transforms(); } return bones[p_bone].global_rest; } @@ -588,6 +649,19 @@ void Skeleton3D::clear_bones() { // Posing api +void Skeleton3D::set_bone_pose(int p_bone, const Transform3D &p_pose) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + + bones.write[p_bone].pose_position = p_pose.origin; + bones.write[p_bone].pose_rotation = p_pose.basis.get_rotation_quaternion(); + bones.write[p_bone].pose_scale = p_pose.basis.get_scale(); + bones.write[p_bone].pose_cache_dirty = true; + if (is_inside_tree()) { + _make_dirty(); + } +} + void Skeleton3D::set_bone_pose_position(int p_bone, const Vector3 &p_position) { const int bone_size = bones.size(); ERR_FAIL_INDEX(p_bone, bone_size); @@ -654,7 +728,7 @@ void Skeleton3D::reset_bone_poses() { Transform3D Skeleton3D::get_bone_pose(int p_bone) const { const int bone_size = bones.size(); ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); - ((Skeleton3D *)this)->bones.write[p_bone].update_pose_cache(); + const_cast<Skeleton3D *>(this)->bones.write[p_bone].update_pose_cache(); return bones[p_bone].pose_cache; } @@ -662,11 +736,15 @@ void Skeleton3D::_make_dirty() { if (dirty) { return; } + dirty = true; + _update_deferred(); +} - if (is_inside_tree()) { - notify_deferred_thread_group(NOTIFICATION_UPDATE_SKELETON); +void Skeleton3D::_update_deferred() { + if (!is_update_needed && !updating && is_inside_tree()) { + is_update_needed = true; + notify_deferred_thread_group(NOTIFICATION_UPDATE_SKELETON); // It must never be called more than once in a single frame. } - dirty = true; } void Skeleton3D::localize_rests() { @@ -687,173 +765,6 @@ void Skeleton3D::localize_rests() { } } -void Skeleton3D::set_animate_physical_bones(bool p_enabled) { - animate_physical_bones = p_enabled; - - if (Engine::get_singleton()->is_editor_hint() == false) { - bool sim = false; - for (int i = 0; i < bones.size(); i += 1) { - if (bones[i].physical_bone) { - bones[i].physical_bone->reset_physics_simulation_state(); - if (bones[i].physical_bone->is_simulating_physics()) { - sim = true; - } - } - } - set_physics_process_internal(sim == false && p_enabled); - } -} - -bool Skeleton3D::get_animate_physical_bones() const { - return animate_physical_bones; -} - -void Skeleton3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - ERR_FAIL_COND(bones[p_bone].physical_bone); - ERR_FAIL_NULL(p_physical_bone); - bones.write[p_bone].physical_bone = p_physical_bone; - - _rebuild_physical_bones_cache(); -} - -void Skeleton3D::unbind_physical_bone_from_bone(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX(p_bone, bone_size); - bones.write[p_bone].physical_bone = nullptr; - - _rebuild_physical_bones_cache(); -} - -PhysicalBone3D *Skeleton3D::get_physical_bone(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - return bones[p_bone].physical_bone; -} - -PhysicalBone3D *Skeleton3D::get_physical_bone_parent(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - if (bones[p_bone].cache_parent_physical_bone) { - return bones[p_bone].cache_parent_physical_bone; - } - - return _get_physical_bone_parent(p_bone); -} - -PhysicalBone3D *Skeleton3D::_get_physical_bone_parent(int p_bone) { - const int bone_size = bones.size(); - ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr); - - const int parent_bone = bones[p_bone].parent; - if (0 > parent_bone) { - return nullptr; - } - - PhysicalBone3D *pb = bones[parent_bone].physical_bone; - if (pb) { - return pb; - } else { - return get_physical_bone_parent(parent_bone); - } -} - -void Skeleton3D::_rebuild_physical_bones_cache() { - const int b_size = bones.size(); - for (int i = 0; i < b_size; ++i) { - PhysicalBone3D *parent_pb = _get_physical_bone_parent(i); - if (parent_pb != bones[i].cache_parent_physical_bone) { - bones.write[i].cache_parent_physical_bone = parent_pb; - if (bones[i].physical_bone) { - bones[i].physical_bone->_on_bone_parent_changed(); - } - } - } -} - -void _pb_stop_simulation(Node *p_node) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _pb_stop_simulation(p_node->get_child(i)); - } - - PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); - if (pb) { - pb->set_simulate_physics(false); - } -} - -void Skeleton3D::physical_bones_stop_simulation() { - _pb_stop_simulation(this); - if (Engine::get_singleton()->is_editor_hint() == false && animate_physical_bones) { - set_physics_process_internal(true); - } -} - -void _pb_start_simulation(const Skeleton3D *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones); - } - - PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node); - if (pb) { - if (p_sim_bones.is_empty()) { // If no bones is specified, activate ragdoll on full body. - pb->set_simulate_physics(true); - } else { - for (int i = p_sim_bones.size() - 1; 0 <= i; --i) { - if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) { - pb->set_simulate_physics(true); - break; - } - } - } - } -} - -void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) { - set_physics_process_internal(false); - - Vector<int> sim_bones; - if (p_bones.size() > 0) { - sim_bones.resize(p_bones.size()); - int c = 0; - for (int i = sim_bones.size() - 1; 0 <= i; --i) { - int bone_id = find_bone(p_bones[i]); - if (bone_id != -1) { - sim_bones.write[c++] = bone_id; - } - } - sim_bones.resize(c); - } - - _pb_start_simulation(this, this, sim_bones); -} - -void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) { - for (int i = p_node->get_child_count() - 1; 0 <= i; --i) { - _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception); - } - - CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_node); - if (co) { - if (p_add) { - PhysicsServer3D::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception); - } else { - PhysicsServer3D::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception); - } - } -} - -void Skeleton3D::physical_bones_add_collision_exception(RID p_exception) { - _physical_bones_add_remove_collision_exception(true, this, p_exception); -} - -void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { - _physical_bones_add_remove_collision_exception(false, this, p_exception); -} - void Skeleton3D::_skin_changed() { _make_dirty(); } @@ -927,18 +838,23 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) { } void Skeleton3D::force_update_all_dirty_bones() { - if (dirty) { - const_cast<Skeleton3D *>(this)->notification(NOTIFICATION_UPDATE_SKELETON); + if (!dirty) { + return; } + force_update_all_bone_transforms(); } void Skeleton3D::force_update_all_bone_transforms() { _update_process_order(); - for (int i = 0; i < parentless_bones.size(); i++) { force_update_bone_children_transforms(parentless_bones[i]); } rest_dirty = false; + dirty = false; + if (updating) { + return; + } + emit_signal(SceneStringNames::get_singleton()->pose_updated); } void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { @@ -961,32 +877,43 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { Transform3D pose = b.pose_cache; if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * pose; - b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose; + b.global_pose = bonesptr[b.parent].global_pose * pose; } else { - b.pose_global = pose; - b.pose_global_no_override = pose; + b.global_pose = pose; } } else { if (b.parent >= 0) { - b.pose_global = bonesptr[b.parent].pose_global * b.rest; - b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest; + b.global_pose = bonesptr[b.parent].global_pose * b.rest; } else { - b.pose_global = b.rest; - b.pose_global_no_override = b.rest; + b.global_pose = b.rest; } } if (rest_dirty) { b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest; } +#ifndef DISABLE_DEPRECATED + if (bone_enabled) { + Transform3D pose = b.pose_cache; + if (b.parent >= 0) { + b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * pose; + } else { + b.pose_global_no_override = pose; + } + } else { + if (b.parent >= 0) { + b.pose_global_no_override = bonesptr[b.parent].pose_global_no_override * b.rest; + } else { + b.pose_global_no_override = 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.global_pose = b.global_pose.interpolate_with(b.global_pose_override, b.global_pose_override_amount); } - if (b.global_pose_override_reset) { b.global_pose_override_amount = 0.0; } +#endif // _DISABLE_DEPRECATED // Add the bone's children to the list of bones to be processed. int child_bone_size = b.child_bones.size(); @@ -998,6 +925,72 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) { } } +void Skeleton3D::_find_modifiers() { + if (!modifiers_dirty) { + return; + } + modifiers.clear(); + for (int i = 0; i < get_child_count(); i++) { + SkeletonModifier3D *c = Object::cast_to<SkeletonModifier3D>(get_child(i)); + if (c) { + modifiers.push_back(c->get_instance_id()); + } + } + modifiers_dirty = false; +} + +void Skeleton3D::_process_modifiers() { + for (const ObjectID &oid : modifiers) { + Object *t_obj = ObjectDB::get_instance(oid); + if (!t_obj) { + continue; + } + SkeletonModifier3D *mod = cast_to<SkeletonModifier3D>(t_obj); + if (!mod) { + continue; + } + real_t influence = mod->get_influence(); + if (influence < 1.0) { + LocalVector<Transform3D> old_poses; + for (int i = 0; i < get_bone_count(); i++) { + old_poses.push_back(get_bone_pose(i)); + } + mod->process_modification(); + LocalVector<Transform3D> new_poses; + for (int i = 0; i < get_bone_count(); i++) { + new_poses.push_back(get_bone_pose(i)); + } + for (int i = 0; i < get_bone_count(); i++) { + if (old_poses[i] == new_poses[i]) { + continue; // Avoid unneeded calculation. + } + set_bone_pose(i, old_poses[i].interpolate_with(new_poses[i], influence)); + } + } else { + mod->process_modification(); + } + force_update_all_dirty_bones(); + } +} + +void Skeleton3D::add_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + +void Skeleton3D::move_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + +void Skeleton3D::remove_child_notify(Node *p_child) { + if (Object::cast_to<SkeletonModifier3D>(p_child)) { + _make_modifiers_dirty(); + } +} + void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton3D::add_bone); ClassDB::bind_method(D_METHOD("find_bone", "name"), &Skeleton3D::find_bone); @@ -1028,6 +1021,7 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear_bones"), &Skeleton3D::clear_bones); ClassDB::bind_method(D_METHOD("get_bone_pose", "bone_idx"), &Skeleton3D::get_bone_pose); + ClassDB::bind_method(D_METHOD("set_bone_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_pose); ClassDB::bind_method(D_METHOD("set_bone_pose_position", "bone_idx", "position"), &Skeleton3D::set_bone_pose_position); ClassDB::bind_method(D_METHOD("set_bone_pose_rotation", "bone_idx", "rotation"), &Skeleton3D::set_bone_pose_rotation); ClassDB::bind_method(D_METHOD("set_bone_pose_scale", "bone_idx", "scale"), &Skeleton3D::set_bone_pose_scale); @@ -1042,11 +1036,8 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_bone_enabled", "bone_idx"), &Skeleton3D::is_bone_enabled); ClassDB::bind_method(D_METHOD("set_bone_enabled", "bone_idx", "enabled"), &Skeleton3D::set_bone_enabled, DEFVAL(true)); - ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override); - ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false)); - ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override); ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose); - ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override); + ClassDB::bind_method(D_METHOD("set_bone_global_pose", "bone_idx", "pose"), &Skeleton3D::set_bone_global_pose); ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms); ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms); @@ -1057,27 +1048,125 @@ void Skeleton3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only); ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only); - ClassDB::bind_method(D_METHOD("set_animate_physical_bones", "enabled"), &Skeleton3D::set_animate_physical_bones); - ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones); - - ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation); - ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array())); - ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception); - ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); + ClassDB::bind_method(D_METHOD("set_modifier_callback_mode_process", "mode"), &Skeleton3D::set_modifier_callback_mode_process); + ClassDB::bind_method(D_METHOD("get_modifier_callback_mode_process"), &Skeleton3D::get_modifier_callback_mode_process); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only"); -#ifndef _3D_DISABLED - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "animate_physical_bones"), "set_animate_physical_bones", "get_animate_physical_bones"); -#endif // _3D_DISABLED + + ADD_GROUP("Modifier", "modifier_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "modifier_callback_mode_process", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_modifier_callback_mode_process", "get_modifier_callback_mode_process"); ADD_SIGNAL(MethodInfo("pose_updated")); ADD_SIGNAL(MethodInfo("bone_pose_changed", PropertyInfo(Variant::INT, "bone_idx"))); ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx"))); + ADD_SIGNAL(MethodInfo("bone_list_changed")); ADD_SIGNAL(MethodInfo("show_rest_only_changed")); BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON); + BIND_ENUM_CONSTANT(MODIFIER_CALLBACK_MODE_PROCESS_PHYSICS); + BIND_ENUM_CONSTANT(MODIFIER_CALLBACK_MODE_PROCESS_IDLE); + +#ifndef DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("clear_bones_global_pose_override"), &Skeleton3D::clear_bones_global_pose_override); + ClassDB::bind_method(D_METHOD("set_bone_global_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_global_pose_override, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_bone_global_pose_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_override); + ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override); + + ClassDB::bind_method(D_METHOD("set_animate_physical_bones", "enabled"), &Skeleton3D::set_animate_physical_bones); + ClassDB::bind_method(D_METHOD("get_animate_physical_bones"), &Skeleton3D::get_animate_physical_bones); + ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton3D::physical_bones_stop_simulation); + ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton3D::physical_bones_start_simulation_on, DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception); + ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception); +#endif // _DISABLE_DEPRECATED +} + +#ifndef DISABLE_DEPRECATED +void Skeleton3D::clear_bones_global_pose_override() { + for (int i = 0; i < bones.size(); i += 1) { + bones.write[i].global_pose_override_amount = 0; + bones.write[i].global_pose_override_reset = true; + } + _make_dirty(); +} + +void Skeleton3D::set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) { + const int bone_size = bones.size(); + ERR_FAIL_INDEX(p_bone, bone_size); + 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(); +} + +Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); + return bones[p_bone].global_pose_override; +} + +Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const { + const int bone_size = bones.size(); + ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D()); + const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones(); + return bones[p_bone].pose_global_no_override; +} + +Node *Skeleton3D::get_simulator() { + return simulator; +} + +void Skeleton3D::set_animate_physical_bones(bool p_enabled) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->set_active(p_enabled); +} + +bool Skeleton3D::get_animate_physical_bones() const { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return false; + } + return sim->is_active(); +} + +void Skeleton3D::physical_bones_stop_simulation() { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_stop_simulation(); + sim->set_active(false); +} + +void Skeleton3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->set_active(true); + sim->physical_bones_start_simulation_on(p_bones); +} + +void Skeleton3D::physical_bones_add_collision_exception(RID p_exception) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_add_collision_exception(p_exception); +} + +void Skeleton3D::physical_bones_remove_collision_exception(RID p_exception) { + PhysicalBoneSimulator3D *sim = cast_to<PhysicalBoneSimulator3D>(simulator); + if (!sim) { + return; + } + sim->physical_bones_remove_collision_exception(p_exception); } +#endif // _DISABLE_DEPRECATED Skeleton3D::Skeleton3D() { } |