From 62a98c4f4cbb8095b615c30f3f889ddbaa2cf16c Mon Sep 17 00:00:00 2001 From: Invertex Date: Fri, 19 Jan 2024 22:25:01 -0800 Subject: [PATCH] misc tweaks --- .../post_import_plugin_skeleton_renamer.cpp | 11 ++ editor/import/resource_importer_scene.cpp | 2 + scene/register_scene_types.cpp | 3 +- scene/resources/bindpose_data.cpp | 176 ++++++++++++++++++ scene/resources/bindpose_data.h | 57 ++++++ 5 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 scene/resources/bindpose_data.cpp create mode 100644 scene/resources/bindpose_data.h diff --git a/editor/import/post_import_plugin_skeleton_renamer.cpp b/editor/import/post_import_plugin_skeleton_renamer.cpp index adeea51dae9d..2f812bd40a30 100644 --- a/editor/import/post_import_plugin_skeleton_renamer.cpp +++ b/editor/import/post_import_plugin_skeleton_renamer.cpp @@ -36,6 +36,7 @@ #include "scene/3d/skeleton_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/bone_map.h" +#include void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImportCategory p_category, List *r_options) { if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) { @@ -53,6 +54,16 @@ void PostImportPluginSkeletonRenamer::_internal_process(InternalImportCategory p } Skeleton3D *skeleton = Object::cast_to(p_node); + // Store Skeleton's bind-pose in this file's .import data, and potentially load a Bindpose to use from another file. + { + Object *bindpose_data = p_options["import/bindpose_data"].get_validated_object(); + if (bindpose_data && bindpose_data->is_class("BindposeData")) { + print_line("set bindpose"); + BindposeData *bpose = Object::cast_to(bindpose_data); + bpose->process_skeleton(p_base_scene, skeleton); + } + } + // Rename bones in Skeleton3D. { int len = skeleton->get_bone_count(); diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index c895c2f6c5b0..f39131f81919 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -46,6 +46,7 @@ #include "scene/3d/vehicle_body_3d.h" #include "scene/animation/animation_player.h" #include "scene/resources/animation.h" +#include "scene/resources/bindpose_data.h" #include "scene/resources/box_shape_3d.h" #include "scene/resources/importer_mesh.h" #include "scene/resources/packed_scene.h" @@ -1742,6 +1743,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p } break; case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "import/bindpose_data", PROPERTY_HINT_RESOURCE_TYPE, "BindposeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant())); r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "retarget/bone_map", PROPERTY_HINT_RESOURCE_TYPE, "BoneMap", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant())); } break; default: { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3727c788fde9..df83850110ac 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -145,6 +145,7 @@ #include "scene/resources/atlas_texture.h" #include "scene/resources/audio_stream_polyphonic.h" #include "scene/resources/audio_stream_wav.h" +#include "scene/resources/bindpose_data.h" #include "scene/resources/bit_map.h" #include "scene/resources/bone_map.h" #include "scene/resources/box_shape_3d.h" @@ -930,7 +931,7 @@ void register_scene_types() { GDREGISTER_CLASS(SkeletonProfile); GDREGISTER_CLASS(SkeletonProfileHumanoid); GDREGISTER_CLASS(BoneMap); - + GDREGISTER_CLASS(BindposeData); OS::get_singleton()->yield(); // may take time to init GDREGISTER_CLASS(AudioStreamPlayer); diff --git a/scene/resources/bindpose_data.cpp b/scene/resources/bindpose_data.cpp new file mode 100644 index 000000000000..84604bcf6bc4 --- /dev/null +++ b/scene/resources/bindpose_data.cpp @@ -0,0 +1,176 @@ +/**************************************************************************/ +/* bindpose_data.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "bindpose_data.h" +#include "scene/3d/skeleton_3d.h" +#include + +bool BindposeData::_set(const StringName &p_path, const Variant &p_value) { + String path = p_path; + if (path == "source_pose") { + source_pose = p_value; + return true; + } + if (path == "store_source_bindpose") { + store_source_bindpose = p_value; + return true; + } + if (path == "load_source_bindpose_from_other") { + load_source_bindpose_from_other = p_value; + return true; + } + return false; +} + +bool BindposeData::_get(const StringName &p_path, Variant &r_ret) const { + String path = p_path; + if (path == "source_pose") { + r_ret = source_pose; + return true; + } + if (path == "store_source_bindpose") { + r_ret = store_source_bindpose; + return true; + } + if (path == "load_source_bindpose_from_other") { + r_ret = load_source_bindpose_from_other; + return true; + } + return false; +} + +void BindposeData::_get_property_list(List *p_list) const { + p_list->push_back(PropertyInfo(Variant::BOOL, "store_source_bindpose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED)); + if (!store_source_bindpose) { + p_list->push_back(PropertyInfo(Variant::STRING, "load_source_bindpose_from_other", PROPERTY_HINT_FILE, "*.import, *.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED)); + } + p_list->push_back(PropertyInfo(Variant::DICTIONARY, "source_pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR)); +} + + +Dictionary BindposeData::get_referenced_pose(Node *p_root, Node *p_skeleton) { + Skeleton3D *skeleton = Object::cast_to(p_skeleton); + Dictionary empty; + print_line("get ref pose"); + if (!skeleton) { + print_error("Value passed in that was not a Skeleton3D."); + return empty; + } + String target_import_path = load_source_bindpose_from_other; + if (!load_source_bindpose_from_other.is_empty()) { + if (!FileAccess::exists(target_import_path)) { + print_error("Could find file at: " + target_import_path); + } else { + Ref cf; + cf.instantiate(); + Error err = cf->load(target_import_path); + if (err == OK && cf->has_section_key("params", "_subresources")) { + Dictionary subresources = cf->get_value("params", "_subresources"); + print_line("get params"); + Dictionary nodes; + if (subresources.has("nodes")) { + nodes = subresources["nodes"]; + String skeleton_path = "PATH:" + p_root->get_path_to(p_skeleton); + print_line("found skel"); + print_line(skeleton_path); + + if (nodes.has(skeleton_path)) { + print_line("has skelly path"); + Dictionary skeleton_data = nodes[skeleton_path]; + if (skeleton_data.has("import/bindpose_data")) { + print_line("skelly has bindpose"); + BindposeData *bindpose_data = Object::cast_to(skeleton_data["import/bindpose_data"]); + print_line(bindpose_data->store_source_bindpose); + return bindpose_data->source_pose; + } + + } + } + } + } + } + return empty; +} + +void BindposeData::process_skeleton(Node *p_root, Node *p_skeleton) { + Skeleton3D *skeleton = Object::cast_to(p_skeleton); + if (!skeleton) { + print_error("Value passed in that was not a Skeleton3D."); + return; + } + if (store_source_bindpose) { + source_pose["basis"] = skeleton->get_basis(); + + int bone_count = skeleton->get_bone_count(); + for (int i = 0; i < bone_count; i++) { + source_pose[skeleton->get_bone_name(i)] = skeleton->get_bone_rest(i); + } + } + Dictionary &referenced_pose = get_referenced_pose(p_root, p_skeleton); + if (!referenced_pose.is_empty()) { + Basis skeleton_basis = referenced_pose["basis"]; + skeleton->set_basis(skeleton_basis); + + int bone_count = skeleton->get_bone_count(); + for (int b = 0; b < bone_count; b++) { + String bone_name = skeleton->get_bone_name(b); + if (referenced_pose.has(bone_name)) { + print_line("Changed bone: " + bone_name); + Transform3D pose = referenced_pose[bone_name]; + skeleton->set_bone_rest(b, pose); + skeleton->set_bone_pose_rotation(b, pose.basis.get_quaternion()); + skeleton->set_bone_global_pose_override(b, pose, true); + } + } + //skeleton->reset_bone_poses(); + } + notify_property_list_changed(); +} + +void BindposeData::_bind_methods() { + ClassDB::bind_method(D_METHOD("process_skeleton", "p_root", "skeleton"), &BindposeData::process_skeleton); + ClassDB::bind_method(D_METHOD("get_referenced_pose", "p_root", "skeleton"), &BindposeData::get_referenced_pose); + ADD_SIGNAL(MethodInfo("source_bindpose_updated")); +} + +void BindposeData::_validate_property(PropertyInfo &property) const { + if (property.name == "import/bindpose_data") { + property.usage = PROPERTY_USAGE_NO_EDITOR; + } +} + +BindposeData::BindposeData() { + store_source_bindpose = false; +} + +BindposeData::~BindposeData() { +} + +////////////////////////////////////// diff --git a/scene/resources/bindpose_data.h b/scene/resources/bindpose_data.h new file mode 100644 index 000000000000..b5d3295defba --- /dev/null +++ b/scene/resources/bindpose_data.h @@ -0,0 +1,57 @@ +/**************************************************************************/ +/* bindpose_data.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef BINDPOSE_DATA_H +#define BINDPOSE_DATA_H + +#include "core/io/resource.h" + +class BindposeData : public Resource { + GDCLASS(BindposeData, Resource); + bool store_source_bindpose; + String load_source_bindpose_from_other; + Dictionary source_pose; + +protected: + bool _get(const StringName &p_path, Variant &r_ret) const; + bool _set(const StringName &p_path, const Variant &p_value); + void _validate_property(PropertyInfo &p_property) const; + void _get_property_list(List *p_list) const; + static void _bind_methods(); + +public: + void process_skeleton(Node *p_root, Node *p_skeleton); + Dictionary get_referenced_pose(Node *p_root, Node *p_skeleton); + + BindposeData(); + ~BindposeData(); +}; + +#endif // BINDPOSE_DATA_H