feat: updated engine version to 4.4-rc1
This commit is contained in:
parent
ee00efde1f
commit
21ba8e33af
5459 changed files with 1128836 additions and 198305 deletions
|
|
@ -31,9 +31,7 @@
|
|||
#include "skeleton_3d.h"
|
||||
#include "skeleton_3d.compat.inc"
|
||||
|
||||
#include "core/variant/type_info.h"
|
||||
#include "scene/3d/skeleton_modifier_3d.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
#include "scene/3d/physical_bone_simulator_3d.h"
|
||||
#endif // _DISABLE_DEPRECATED
|
||||
|
|
@ -69,19 +67,19 @@ 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")) {
|
||||
if (p_path == SNAME("animate_physical_bones")) {
|
||||
set_animate_physical_bones(p_value);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
String path = p_path;
|
||||
|
||||
if (!path.begins_with("bones/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
uint32_t which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
|
||||
if (which == bones.size() && what == "name") {
|
||||
|
|
@ -89,7 +87,7 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
|
|||
return true;
|
||||
}
|
||||
|
||||
ERR_FAIL_INDEX_V(which, bones.size(), false);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(which, bones.size(), false);
|
||||
|
||||
if (what == "parent") {
|
||||
set_bone_parent(which, p_value);
|
||||
|
|
@ -103,6 +101,8 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
|
|||
set_bone_pose_rotation(which, p_value);
|
||||
} else if (what == "scale") {
|
||||
set_bone_pose_scale(which, p_value);
|
||||
} else if (what == "bone_meta") {
|
||||
set_bone_meta(which, path.get_slicec('/', 3), p_value);
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
} else if (what == "pose" || what == "bound_children") {
|
||||
// Kept for compatibility from 3.x to 4.x.
|
||||
|
|
@ -139,22 +139,22 @@ 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")) {
|
||||
if (p_path == SNAME("animate_physical_bones")) {
|
||||
r_ret = get_animate_physical_bones();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
String path = p_path;
|
||||
|
||||
if (!path.begins_with("bones/")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
uint32_t which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
|
||||
ERR_FAIL_INDEX_V(which, bones.size(), false);
|
||||
ERR_FAIL_UNSIGNED_INDEX_V(which, bones.size(), false);
|
||||
|
||||
if (what == "name") {
|
||||
r_ret = get_bone_name(which);
|
||||
|
|
@ -170,6 +170,8 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
|
|||
r_ret = get_bone_pose_rotation(which);
|
||||
} else if (what == "scale") {
|
||||
r_ret = get_bone_pose_scale(which);
|
||||
} else if (what == "bone_meta") {
|
||||
r_ret = get_bone_meta(which, path.get_slicec('/', 3));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -178,15 +180,20 @@ bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
|
|||
}
|
||||
|
||||
void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
const String prep = vformat("%s/%d/", PNAME("bones"), i);
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, prep + PNAME("name"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, prep + PNAME("parent"), PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + PNAME("rest"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, prep + PNAME("enabled"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("position"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::QUATERNION, prep + PNAME("rotation"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
for (uint32_t i = 0; i < bones.size(); i++) {
|
||||
const String prep = vformat("%s/%d/", "bones", i);
|
||||
p_list->push_back(PropertyInfo(Variant::STRING, prep + "name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::INT, prep + "parent", PROPERTY_HINT_RANGE, "-1," + itos(bones.size() - 1) + ",1", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::TRANSFORM3D, prep + "rest", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::QUATERNION, prep + "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
|
||||
|
||||
for (const KeyValue<StringName, Variant> &K : bones[i].metadata) {
|
||||
PropertyInfo pi = PropertyInfo(bones[i].metadata[K.key].get_type(), prep + "bone_meta/" + K.key, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR);
|
||||
p_list->push_back(pi);
|
||||
}
|
||||
}
|
||||
|
||||
for (PropertyInfo &E : *p_list) {
|
||||
|
|
@ -227,12 +234,12 @@ void Skeleton3D::_validate_property(PropertyInfo &p_property) const {
|
|||
}
|
||||
}
|
||||
|
||||
void Skeleton3D::_update_process_order() {
|
||||
void Skeleton3D::_update_process_order() const {
|
||||
if (!process_order_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
Bone *bonesptr = bones.ptrw();
|
||||
Bone *bonesptr = bones.ptr();
|
||||
int len = bones.size();
|
||||
|
||||
parentless_bones.clear();
|
||||
|
|
@ -263,18 +270,18 @@ void Skeleton3D::_update_process_order() {
|
|||
}
|
||||
}
|
||||
|
||||
bones_backup.resize(bones.size());
|
||||
|
||||
concatenated_bone_names = StringName();
|
||||
|
||||
_update_bones_nested_set();
|
||||
|
||||
process_order_dirty = false;
|
||||
|
||||
emit_signal("bone_list_changed");
|
||||
const_cast<Skeleton3D *>(this)->emit_signal("bone_list_changed");
|
||||
}
|
||||
|
||||
void Skeleton3D::_update_bone_names() const {
|
||||
String names;
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
for (uint32_t i = 0; i < bones.size(); i++) {
|
||||
if (i > 0) {
|
||||
names += ",";
|
||||
}
|
||||
|
|
@ -315,23 +322,41 @@ void Skeleton3D::_notification(int p_what) {
|
|||
#ifndef DISABLE_DEPRECATED
|
||||
setup_simulator();
|
||||
#endif // _DISABLE_DEPRECATED
|
||||
update_flags = UPDATE_FLAG_POSE;
|
||||
_notification(NOTIFICATION_UPDATE_SKELETON);
|
||||
} break;
|
||||
#ifdef TOOLS_ENABLED
|
||||
case NOTIFICATION_EDITOR_PRE_SAVE: {
|
||||
saving = true;
|
||||
} break;
|
||||
case NOTIFICATION_EDITOR_POST_SAVE: {
|
||||
saving = false;
|
||||
} break;
|
||||
#endif // TOOLS_ENABLED
|
||||
case NOTIFICATION_UPDATE_SKELETON: {
|
||||
// Update bone transforms to apply unprocessed poses.
|
||||
force_update_all_dirty_bones();
|
||||
|
||||
updating = true;
|
||||
|
||||
Bone *bonesptr = bones.ptrw();
|
||||
Bone *bonesptr = bones.ptr();
|
||||
int len = bones.size();
|
||||
|
||||
thread_local LocalVector<bool> bone_global_pose_dirty_backup;
|
||||
|
||||
// Process modifiers.
|
||||
|
||||
thread_local LocalVector<BonePoseBackup> bones_backup;
|
||||
_find_modifiers();
|
||||
if (!modifiers.is_empty()) {
|
||||
bones_backup.resize(bones.size());
|
||||
// Store unmodified bone poses.
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
bones_backup[i].save(bones[i]);
|
||||
for (uint32_t i = 0; i < bones.size(); i++) {
|
||||
bones_backup[i].save(bonesptr[i]);
|
||||
}
|
||||
// Store dirty flags for global bone poses.
|
||||
bone_global_pose_dirty_backup = bone_global_pose_dirty;
|
||||
|
||||
_process_modifiers();
|
||||
}
|
||||
|
||||
|
|
@ -403,9 +428,11 @@ void Skeleton3D::_notification(int p_what) {
|
|||
|
||||
if (!modifiers.is_empty()) {
|
||||
// Restore unmodified bone poses.
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
bones_backup[i].restore(bones.write[i]);
|
||||
for (uint32_t i = 0; i < bones.size(); i++) {
|
||||
bones_backup[i].restore(bones[i]);
|
||||
}
|
||||
// Restore dirty flags for global bone poses.
|
||||
bone_global_pose_dirty = bone_global_pose_dirty_backup;
|
||||
}
|
||||
|
||||
updating = false;
|
||||
|
|
@ -448,10 +475,111 @@ void Skeleton3D::_make_modifiers_dirty() {
|
|||
_update_deferred(UPDATE_FLAG_MODIFIER);
|
||||
}
|
||||
|
||||
void Skeleton3D::_update_bones_nested_set() const {
|
||||
nested_set_offset_to_bone_index.resize(bones.size());
|
||||
bone_global_pose_dirty.resize(bones.size());
|
||||
_make_bone_global_poses_dirty();
|
||||
|
||||
int offset = 0;
|
||||
for (int bone : parentless_bones) {
|
||||
offset += _update_bone_nested_set(bone, offset);
|
||||
}
|
||||
}
|
||||
|
||||
int Skeleton3D::_update_bone_nested_set(int p_bone, int p_offset) const {
|
||||
Bone &bone = bones[p_bone];
|
||||
int offset = p_offset + 1;
|
||||
int span = 1;
|
||||
|
||||
for (int child_bone : bone.child_bones) {
|
||||
int subspan = _update_bone_nested_set(child_bone, offset);
|
||||
offset += subspan;
|
||||
span += subspan;
|
||||
}
|
||||
|
||||
nested_set_offset_to_bone_index[p_offset] = p_bone;
|
||||
bone.nested_set_offset = p_offset;
|
||||
bone.nested_set_span = span;
|
||||
|
||||
return span;
|
||||
}
|
||||
|
||||
void Skeleton3D::_make_bone_global_poses_dirty() const {
|
||||
for (uint32_t i = 0; i < bone_global_pose_dirty.size(); i++) {
|
||||
bone_global_pose_dirty[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton3D::_make_bone_global_pose_subtree_dirty(int p_bone) const {
|
||||
if (process_order_dirty) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Bone &bone = bones[p_bone];
|
||||
int span_offset = bone.nested_set_offset;
|
||||
// No need to make subtree dirty when bone is already dirty.
|
||||
if (bone_global_pose_dirty[span_offset]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Make global poses of subtree dirty.
|
||||
int span_end = span_offset + bone.nested_set_span;
|
||||
for (int i = span_offset; i < span_end; i++) {
|
||||
bone_global_pose_dirty[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Skeleton3D::_update_bone_global_pose(int p_bone) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
_update_process_order();
|
||||
|
||||
// Global pose is already calculated.
|
||||
int nested_set_offset = bones[p_bone].nested_set_offset;
|
||||
if (!bone_global_pose_dirty[nested_set_offset]) {
|
||||
return;
|
||||
}
|
||||
|
||||
thread_local LocalVector<int> bone_list;
|
||||
bone_list.clear();
|
||||
Transform3D global_pose;
|
||||
|
||||
// Create list of parent bones for which the global pose needs to be recalculated.
|
||||
for (int bone = p_bone; bone >= 0; bone = bones[bone].parent) {
|
||||
int offset = bones[bone].nested_set_offset;
|
||||
// Stop searching when global pose is not dirty.
|
||||
if (!bone_global_pose_dirty[offset]) {
|
||||
global_pose = bones[bone].global_pose;
|
||||
break;
|
||||
}
|
||||
|
||||
bone_list.push_back(bone);
|
||||
}
|
||||
|
||||
// Calculate global poses for all parent bones and the current bone.
|
||||
for (int i = bone_list.size() - 1; i >= 0; i--) {
|
||||
int bone_idx = bone_list[i];
|
||||
Bone &bone = bones[bone_idx];
|
||||
bool bone_enabled = bone.enabled && !show_rest_only;
|
||||
Transform3D bone_pose = bone_enabled ? get_bone_pose(bone_idx) : get_bone_rest(bone_idx);
|
||||
|
||||
global_pose *= bone_pose;
|
||||
#ifndef DISABLE_DEPRECATED
|
||||
if (bone.global_pose_override_amount >= CMP_EPSILON) {
|
||||
global_pose = global_pose.interpolate_with(bone.global_pose_override, bone.global_pose_override_amount);
|
||||
}
|
||||
#endif // _DISABLE_DEPRECATED
|
||||
|
||||
bone.global_pose = global_pose;
|
||||
bone_global_pose_dirty[bone.nested_set_offset] = false;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
const_cast<Skeleton3D *>(this)->force_update_all_dirty_bones();
|
||||
_update_bone_global_pose(p_bone);
|
||||
return bones[p_bone].global_pose;
|
||||
}
|
||||
|
||||
|
|
@ -487,7 +615,7 @@ uint64_t Skeleton3D::get_version() const {
|
|||
}
|
||||
|
||||
int Skeleton3D::add_bone(const String &p_name) {
|
||||
ERR_FAIL_COND_V_MSG(p_name.is_empty() || p_name.contains(":") || p_name.contains("/"), -1, vformat("Bone name cannot be empty or contain ':' or '/'.", p_name));
|
||||
ERR_FAIL_COND_V_MSG(p_name.is_empty() || p_name.contains_char(':') || p_name.contains_char('/'), -1, vformat("Bone name cannot be empty or contain ':' or '/'.", p_name));
|
||||
ERR_FAIL_COND_V_MSG(name_to_bone_index.has(p_name), -1, vformat("Skeleton3D \"%s\" already has a bone with name \"%s\".", to_string(), p_name));
|
||||
|
||||
Bone b;
|
||||
|
|
@ -525,12 +653,63 @@ void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
|
|||
}
|
||||
|
||||
name_to_bone_index.erase(bones[p_bone].name);
|
||||
bones.write[p_bone].name = p_name;
|
||||
bones[p_bone].name = p_name;
|
||||
name_to_bone_index.insert(p_name, p_bone);
|
||||
|
||||
version++;
|
||||
}
|
||||
|
||||
Variant Skeleton3D::get_bone_meta(int p_bone, const StringName &p_key) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX_V(p_bone, bone_size, Variant());
|
||||
|
||||
if (!bones[p_bone].metadata.has(p_key)) {
|
||||
return Variant();
|
||||
}
|
||||
return bones[p_bone].metadata[p_key];
|
||||
}
|
||||
|
||||
TypedArray<StringName> Skeleton3D::_get_bone_meta_list_bind(int p_bone) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX_V(p_bone, bone_size, TypedArray<StringName>());
|
||||
|
||||
TypedArray<StringName> _metaret;
|
||||
for (const KeyValue<StringName, Variant> &K : bones[p_bone].metadata) {
|
||||
_metaret.push_back(K.key);
|
||||
}
|
||||
return _metaret;
|
||||
}
|
||||
|
||||
void Skeleton3D::get_bone_meta_list(int p_bone, List<StringName> *p_list) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
for (const KeyValue<StringName, Variant> &K : bones[p_bone].metadata) {
|
||||
p_list->push_back(K.key);
|
||||
}
|
||||
}
|
||||
|
||||
bool Skeleton3D::has_bone_meta(int p_bone, const StringName &p_key) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX_V(p_bone, bone_size, false);
|
||||
|
||||
return bones[p_bone].metadata.has(p_key);
|
||||
}
|
||||
|
||||
void Skeleton3D::set_bone_meta(int p_bone, const StringName &p_key, const Variant &p_value) {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
if (p_value.get_type() == Variant::NIL) {
|
||||
if (bones[p_bone].metadata.has(p_key)) {
|
||||
bones[p_bone].metadata.erase(p_key);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bones[p_bone].metadata.insert(p_key, p_value, false);
|
||||
}
|
||||
|
||||
bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
|
||||
int parent_of_bone = get_bone_parent(p_bone);
|
||||
|
||||
|
|
@ -555,7 +734,7 @@ void Skeleton3D::set_bone_parent(int p_bone, int p_parent) {
|
|||
ERR_FAIL_COND(p_parent != -1 && (p_parent < 0));
|
||||
ERR_FAIL_COND(p_bone == p_parent);
|
||||
|
||||
bones.write[p_bone].parent = p_parent;
|
||||
bones[p_bone].parent = p_parent;
|
||||
process_order_dirty = true;
|
||||
rest_dirty = true;
|
||||
_make_dirty();
|
||||
|
|
@ -569,11 +748,11 @@ void Skeleton3D::unparent_bone_and_rest(int p_bone) {
|
|||
|
||||
int parent = bones[p_bone].parent;
|
||||
while (parent >= 0) {
|
||||
bones.write[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
|
||||
bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
|
||||
parent = bones[parent].parent;
|
||||
}
|
||||
|
||||
bones.write[p_bone].parent = -1;
|
||||
bones[p_bone].parent = -1;
|
||||
process_order_dirty = true;
|
||||
|
||||
rest_dirty = true;
|
||||
|
|
@ -584,7 +763,7 @@ int Skeleton3D::get_bone_parent(int p_bone) const {
|
|||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
|
||||
if (process_order_dirty) {
|
||||
const_cast<Skeleton3D *>(this)->_update_process_order();
|
||||
_update_process_order();
|
||||
}
|
||||
return bones[p_bone].parent;
|
||||
}
|
||||
|
|
@ -593,14 +772,14 @@ Vector<int> Skeleton3D::get_bone_children(int p_bone) const {
|
|||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX_V(p_bone, bone_size, Vector<int>());
|
||||
if (process_order_dirty) {
|
||||
const_cast<Skeleton3D *>(this)->_update_process_order();
|
||||
_update_process_order();
|
||||
}
|
||||
return bones[p_bone].child_bones;
|
||||
}
|
||||
|
||||
Vector<int> Skeleton3D::get_parentless_bones() const {
|
||||
if (process_order_dirty) {
|
||||
const_cast<Skeleton3D *>(this)->_update_process_order();
|
||||
_update_process_order();
|
||||
}
|
||||
return parentless_bones;
|
||||
}
|
||||
|
|
@ -609,9 +788,10 @@ void Skeleton3D::set_bone_rest(int p_bone, const Transform3D &p_rest) {
|
|||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
bones.write[p_bone].rest = p_rest;
|
||||
bones[p_bone].rest = p_rest;
|
||||
rest_dirty = true;
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
Transform3D Skeleton3D::get_bone_rest(int p_bone) const {
|
||||
const int bone_size = bones.size();
|
||||
|
|
@ -623,7 +803,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)->force_update_all_bone_transforms();
|
||||
_force_update_all_bone_transforms();
|
||||
}
|
||||
return bones[p_bone].global_rest;
|
||||
}
|
||||
|
|
@ -632,9 +812,10 @@ void Skeleton3D::set_bone_enabled(int p_bone, bool p_enabled) {
|
|||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
bones.write[p_bone].enabled = p_enabled;
|
||||
bones[p_bone].enabled = p_enabled;
|
||||
emit_signal(SceneStringName(bone_enabled_changed), p_bone);
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
|
||||
bool Skeleton3D::is_bone_enabled(int p_bone) const {
|
||||
|
|
@ -647,6 +828,7 @@ void Skeleton3D::set_show_rest_only(bool p_enabled) {
|
|||
show_rest_only = p_enabled;
|
||||
emit_signal(SceneStringName(show_rest_only_changed));
|
||||
_make_dirty();
|
||||
_make_bone_global_poses_dirty();
|
||||
}
|
||||
|
||||
bool Skeleton3D::is_show_rest_only() const {
|
||||
|
|
@ -667,12 +849,13 @@ 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;
|
||||
bones[p_bone].pose_position = p_pose.origin;
|
||||
bones[p_bone].pose_rotation = p_pose.basis.get_rotation_quaternion();
|
||||
bones[p_bone].pose_scale = p_pose.basis.get_scale();
|
||||
bones[p_bone].pose_cache_dirty = true;
|
||||
if (is_inside_tree()) {
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -680,30 +863,33 @@ 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);
|
||||
|
||||
bones.write[p_bone].pose_position = p_position;
|
||||
bones.write[p_bone].pose_cache_dirty = true;
|
||||
bones[p_bone].pose_position = p_position;
|
||||
bones[p_bone].pose_cache_dirty = true;
|
||||
if (is_inside_tree()) {
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
}
|
||||
void Skeleton3D::set_bone_pose_rotation(int p_bone, const Quaternion &p_rotation) {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
bones.write[p_bone].pose_rotation = p_rotation;
|
||||
bones.write[p_bone].pose_cache_dirty = true;
|
||||
bones[p_bone].pose_rotation = p_rotation;
|
||||
bones[p_bone].pose_cache_dirty = true;
|
||||
if (is_inside_tree()) {
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
}
|
||||
void Skeleton3D::set_bone_pose_scale(int p_bone, const Vector3 &p_scale) {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone, bone_size);
|
||||
|
||||
bones.write[p_bone].pose_scale = p_scale;
|
||||
bones.write[p_bone].pose_cache_dirty = true;
|
||||
bones[p_bone].pose_scale = p_scale;
|
||||
bones[p_bone].pose_cache_dirty = true;
|
||||
if (is_inside_tree()) {
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -734,7 +920,7 @@ void Skeleton3D::reset_bone_pose(int p_bone) {
|
|||
}
|
||||
|
||||
void Skeleton3D::reset_bone_poses() {
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
for (uint32_t i = 0; i < bones.size(); i++) {
|
||||
reset_bone_pose(i);
|
||||
}
|
||||
}
|
||||
|
|
@ -742,7 +928,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());
|
||||
const_cast<Skeleton3D *>(this)->bones.write[p_bone].update_pose_cache();
|
||||
bones[p_bone].update_pose_cache();
|
||||
return bones[p_bone].pose_cache;
|
||||
}
|
||||
|
||||
|
|
@ -756,6 +942,13 @@ void Skeleton3D::_make_dirty() {
|
|||
|
||||
void Skeleton3D::_update_deferred(UpdateFlag p_update_flag) {
|
||||
if (is_inside_tree()) {
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (saving) {
|
||||
update_flags |= p_update_flag;
|
||||
_notification(NOTIFICATION_UPDATE_SKELETON);
|
||||
return;
|
||||
}
|
||||
#endif //TOOLS_ENABLED
|
||||
if (update_flags == UPDATE_FLAG_NONE && !updating) {
|
||||
notify_deferred_thread_group(NOTIFICATION_UPDATE_SKELETON); // It must never be called more than once in a single frame.
|
||||
}
|
||||
|
|
@ -793,7 +986,7 @@ Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() {
|
|||
|
||||
// Pose changed, rebuild cache of inverses.
|
||||
const Bone *bonesptr = bones.ptr();
|
||||
int len = bones.size();
|
||||
uint32_t len = bones.size();
|
||||
|
||||
// Calculate global rests and invert them.
|
||||
LocalVector<int> bones_to_process;
|
||||
|
|
@ -817,7 +1010,7 @@ Ref<Skin> Skeleton3D::create_skin_from_rest_transforms() {
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
for (uint32_t 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());
|
||||
|
|
@ -853,39 +1046,60 @@ Ref<SkinReference> Skeleton3D::register_skin(const Ref<Skin> &p_skin) {
|
|||
return skin_ref;
|
||||
}
|
||||
|
||||
void Skeleton3D::force_update_deferred() {
|
||||
_make_dirty();
|
||||
}
|
||||
|
||||
void Skeleton3D::force_update_all_dirty_bones() {
|
||||
_force_update_all_dirty_bones();
|
||||
}
|
||||
|
||||
void Skeleton3D::_force_update_all_dirty_bones() const {
|
||||
if (!dirty) {
|
||||
return;
|
||||
}
|
||||
force_update_all_bone_transforms();
|
||||
_force_update_all_bone_transforms();
|
||||
}
|
||||
|
||||
void Skeleton3D::force_update_all_bone_transforms() {
|
||||
_force_update_all_bone_transforms();
|
||||
}
|
||||
|
||||
void Skeleton3D::_force_update_all_bone_transforms() const {
|
||||
_update_process_order();
|
||||
for (int i = 0; i < parentless_bones.size(); i++) {
|
||||
force_update_bone_children_transforms(parentless_bones[i]);
|
||||
_force_update_bone_children_transforms(parentless_bones[i]);
|
||||
}
|
||||
if (rest_dirty) {
|
||||
rest_dirty = false;
|
||||
const_cast<Skeleton3D *>(this)->emit_signal(SNAME("rest_updated"));
|
||||
} else {
|
||||
rest_dirty = false;
|
||||
}
|
||||
rest_dirty = false;
|
||||
dirty = false;
|
||||
if (updating) {
|
||||
return;
|
||||
}
|
||||
emit_signal(SceneStringName(pose_updated));
|
||||
const_cast<Skeleton3D *>(this)->emit_signal(SceneStringName(pose_updated));
|
||||
}
|
||||
|
||||
void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
|
||||
_force_update_bone_children_transforms(p_bone_idx);
|
||||
}
|
||||
|
||||
void Skeleton3D::_force_update_bone_children_transforms(int p_bone_idx) const {
|
||||
const int bone_size = bones.size();
|
||||
ERR_FAIL_INDEX(p_bone_idx, bone_size);
|
||||
|
||||
Bone *bonesptr = bones.ptrw();
|
||||
thread_local LocalVector<int> bones_to_process;
|
||||
bones_to_process.clear();
|
||||
bones_to_process.push_back(p_bone_idx);
|
||||
Bone *bonesptr = bones.ptr();
|
||||
|
||||
uint32_t index = 0;
|
||||
while (index < bones_to_process.size()) {
|
||||
int current_bone_idx = bones_to_process[index];
|
||||
// Loop through nested set.
|
||||
for (int offset = 0; offset < bone_size; offset++) {
|
||||
if (!bone_global_pose_dirty[offset]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int current_bone_idx = nested_set_offset_to_bone_index[offset];
|
||||
Bone &b = bonesptr[current_bone_idx];
|
||||
bool bone_enabled = b.enabled && !show_rest_only;
|
||||
|
||||
|
|
@ -932,13 +1146,7 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
|
|||
}
|
||||
#endif // _DISABLE_DEPRECATED
|
||||
|
||||
// Add the bone's children to the list of bones to be processed.
|
||||
int child_bone_size = b.child_bones.size();
|
||||
for (int i = 0; i < child_bone_size; i++) {
|
||||
bones_to_process.push_back(b.child_bones[i]);
|
||||
}
|
||||
|
||||
index++;
|
||||
bone_global_pose_dirty[offset] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -966,6 +1174,11 @@ void Skeleton3D::_process_modifiers() {
|
|||
if (!mod) {
|
||||
continue;
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (saving && !mod->is_processed_on_saving()) {
|
||||
continue;
|
||||
}
|
||||
#endif //TOOLS_ENABLED
|
||||
real_t influence = mod->get_influence();
|
||||
if (influence < 1.0) {
|
||||
LocalVector<Transform3D> old_poses;
|
||||
|
|
@ -1014,6 +1227,11 @@ void Skeleton3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &Skeleton3D::get_bone_name);
|
||||
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "name"), &Skeleton3D::set_bone_name);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_bone_meta", "bone_idx", "key"), &Skeleton3D::get_bone_meta);
|
||||
ClassDB::bind_method(D_METHOD("get_bone_meta_list", "bone_idx"), &Skeleton3D::_get_bone_meta_list_bind);
|
||||
ClassDB::bind_method(D_METHOD("has_bone_meta", "bone_idx", "key"), &Skeleton3D::has_bone_meta);
|
||||
ClassDB::bind_method(D_METHOD("set_bone_meta", "bone_idx", "key", "value"), &Skeleton3D::set_bone_meta);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_concatenated_bone_names"), &Skeleton3D::get_concatenated_bone_names);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_bone_parent", "bone_idx"), &Skeleton3D::get_bone_parent);
|
||||
|
|
@ -1076,6 +1294,7 @@ void Skeleton3D::_bind_methods() {
|
|||
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("rest_updated"));
|
||||
ADD_SIGNAL(MethodInfo("pose_updated"));
|
||||
ADD_SIGNAL(MethodInfo("skeleton_updated"));
|
||||
ADD_SIGNAL(MethodInfo("bone_enabled_changed", PropertyInfo(Variant::INT, "bone_idx")));
|
||||
|
|
@ -1106,20 +1325,22 @@ void Skeleton3D::_bind_methods() {
|
|||
|
||||
#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;
|
||||
for (uint32_t i = 0; i < bones.size(); i += 1) {
|
||||
bones[i].global_pose_override_amount = 0;
|
||||
bones[i].global_pose_override_reset = true;
|
||||
}
|
||||
_make_dirty();
|
||||
_make_bone_global_poses_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;
|
||||
bones[p_bone].global_pose_override_amount = p_amount;
|
||||
bones[p_bone].global_pose_override = p_pose;
|
||||
bones[p_bone].global_pose_override_reset = !p_persistent;
|
||||
_make_dirty();
|
||||
_make_bone_global_pose_subtree_dirty(p_bone);
|
||||
}
|
||||
|
||||
Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const {
|
||||
|
|
@ -1131,7 +1352,7 @@ Transform3D Skeleton3D::get_bone_global_pose_override(int p_bone) const {
|
|||
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();
|
||||
_force_update_all_dirty_bones();
|
||||
return bones[p_bone].pose_global_no_override;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue