You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-12-03 16:55:53 +00:00
add rest fixer to importer retarget
This commit is contained in:
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "editor/editor_scale.h"
|
||||
#include "editor/import/post_import_plugin_skeleton_renamer.h"
|
||||
#include "editor/import/post_import_plugin_skeleton_rest_fixer.h"
|
||||
#include "editor/import/scene_import_settings.h"
|
||||
|
||||
void BoneMapperButton::fetch_textures() {
|
||||
@@ -71,6 +72,10 @@ void BoneMapperButton::set_state(BoneMapState p_state) {
|
||||
}
|
||||
}
|
||||
|
||||
bool BoneMapperButton::is_require() const {
|
||||
return require;
|
||||
}
|
||||
|
||||
void BoneMapperButton::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
@@ -79,8 +84,9 @@ void BoneMapperButton::_notification(int p_what) {
|
||||
}
|
||||
}
|
||||
|
||||
BoneMapperButton::BoneMapperButton(const StringName p_profile_bone_name, bool p_selected) {
|
||||
BoneMapperButton::BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected) {
|
||||
profile_bone_name = p_profile_bone_name;
|
||||
require = p_require;
|
||||
selected = p_selected;
|
||||
}
|
||||
|
||||
@@ -89,7 +95,7 @@ BoneMapperButton::~BoneMapperButton() {
|
||||
|
||||
void BoneMapperItem::create_editor() {
|
||||
skeleton_bone_selector = memnew(EditorPropertyTextEnum);
|
||||
skeleton_bone_selector->setup(skeleton_bone_names);
|
||||
skeleton_bone_selector->setup(skeleton_bone_names, false, true);
|
||||
skeleton_bone_selector->set_label(profile_bone_name);
|
||||
skeleton_bone_selector->set_selectable(false);
|
||||
skeleton_bone_selector->set_object_and_property(bone_map.ptr(), "bone_map/" + String(profile_bone_name));
|
||||
@@ -251,7 +257,7 @@ void BoneMapper::recreate_editor() {
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (profile->get_group(i) == profile->get_group_name(current_group_idx)) {
|
||||
BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), current_bone_idx == i));
|
||||
BoneMapperButton *mb = memnew(BoneMapperButton(profile->get_bone_name(i), profile->is_require(i), current_bone_idx == i));
|
||||
mb->connect("pressed", callable_mp(this, &BoneMapper::set_current_bone_idx), varray(i), CONNECT_DEFERRED);
|
||||
mb->set_h_grow_direction(GROW_DIRECTION_BOTH);
|
||||
mb->set_v_grow_direction(GROW_DIRECTION_BOTH);
|
||||
@@ -284,8 +290,6 @@ void BoneMapper::recreate_items() {
|
||||
Ref<SkeletonProfile> profile = bone_map->get_profile();
|
||||
if (profile.is_valid()) {
|
||||
PackedStringArray skeleton_bone_names;
|
||||
skeleton_bone_names.push_back(String());
|
||||
|
||||
int len = skeleton->get_bone_count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
skeleton_bone_names.push_back(skeleton->get_bone_name(i));
|
||||
@@ -314,7 +318,11 @@ void BoneMapper::_update_state() {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_ERROR);
|
||||
}
|
||||
} else {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_UNSET);
|
||||
if (bone_mapper_buttons[i]->is_require()) {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_ERROR);
|
||||
} else {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_UNSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -396,9 +404,12 @@ void BoneMapEditor::_notification(int p_what) {
|
||||
create_editors();
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
if (!bone_mapper) {
|
||||
return;
|
||||
}
|
||||
remove_child(bone_mapper);
|
||||
bone_mapper->queue_delete();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,4 +447,8 @@ BoneMapEditorPlugin::BoneMapEditorPlugin() {
|
||||
Ref<PostImportPluginSkeletonRenamer> post_import_plugin_renamer;
|
||||
post_import_plugin_renamer.instantiate();
|
||||
add_scene_post_import_plugin(post_import_plugin_renamer);
|
||||
|
||||
Ref<PostImportPluginSkeletonRestFixer> post_import_plugin_rest_fixer;
|
||||
post_import_plugin_rest_fixer.instantiate();
|
||||
add_scene_post_import_plugin(post_import_plugin_rest_fixer);
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ public:
|
||||
private:
|
||||
StringName profile_bone_name;
|
||||
bool selected = false;
|
||||
bool require = false;
|
||||
|
||||
TextureRect *circle;
|
||||
|
||||
@@ -65,7 +66,9 @@ public:
|
||||
StringName get_profile_bone_name() const;
|
||||
void set_state(BoneMapState p_state);
|
||||
|
||||
BoneMapperButton(const StringName p_profile_bone_name, bool p_selected);
|
||||
bool is_require() const;
|
||||
|
||||
BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected);
|
||||
~BoneMapperButton();
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "scene/3d/mesh_instance_3d.h"
|
||||
#include "scene/3d/physics_body_3d.h"
|
||||
#include "scene/resources/capsule_shape_3d.h"
|
||||
#include "scene/resources/skeleton_profile.h"
|
||||
#include "scene/resources/sphere_shape_3d.h"
|
||||
#include "scene/resources/surface_tool.h"
|
||||
|
||||
@@ -250,6 +251,10 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
|
||||
create_physical_skeleton();
|
||||
break;
|
||||
}
|
||||
case SKELETON_OPTION_EXPORT_SKELETON_PROFILE: {
|
||||
export_skeleton_profile();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +456,73 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
|
||||
return physical_bone;
|
||||
}
|
||||
|
||||
void Skeleton3DEditor::export_skeleton_profile() {
|
||||
file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
|
||||
file_dialog->set_title(TTR("Export Skeleton Profile As..."));
|
||||
|
||||
List<String> exts;
|
||||
ResourceLoader::get_recognized_extensions_for_type("SkeletonProfile", &exts);
|
||||
file_dialog->clear_filters();
|
||||
for (const String &K : exts) {
|
||||
file_dialog->add_filter("*." + K);
|
||||
}
|
||||
|
||||
file_dialog->popup_file_dialog();
|
||||
}
|
||||
|
||||
void Skeleton3DEditor::_file_selected(const String &p_file) {
|
||||
// Export SkeletonProfile.
|
||||
Ref<SkeletonProfile> sp(memnew(SkeletonProfile));
|
||||
|
||||
// Build SkeletonProfile.
|
||||
sp->set_group_size(1);
|
||||
|
||||
Vector<Vector2> handle_positions;
|
||||
Vector2 position_max;
|
||||
Vector2 position_min;
|
||||
|
||||
int len = skeleton->get_bone_count();
|
||||
sp->set_bone_size(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
sp->set_bone_name(i, skeleton->get_bone_name(i));
|
||||
int parent = skeleton->get_bone_parent(i);
|
||||
if (parent >= 0) {
|
||||
sp->set_bone_parent(i, skeleton->get_bone_name(parent));
|
||||
}
|
||||
sp->set_reference_pose(i, skeleton->get_bone_rest(i));
|
||||
|
||||
Transform3D grest = skeleton->get_bone_global_rest(i);
|
||||
handle_positions.append(Vector2(grest.origin.x, grest.origin.y));
|
||||
if (i == 0) {
|
||||
position_max = Vector2(grest.origin.x, grest.origin.y);
|
||||
position_min = Vector2(grest.origin.x, grest.origin.y);
|
||||
} else {
|
||||
position_max.x = MAX(grest.origin.x, position_max.x);
|
||||
position_max.y = MAX(grest.origin.y, position_max.y);
|
||||
position_min.x = MIN(grest.origin.x, position_min.x);
|
||||
position_min.y = MIN(grest.origin.y, position_min.y);
|
||||
}
|
||||
}
|
||||
|
||||
// Layout handles provisionaly.
|
||||
Vector2 bound = Vector2(position_max.x - position_min.x, position_max.y - position_min.y);
|
||||
Vector2 center = Vector2((position_max.x + position_min.x) * 0.5, (position_max.y + position_min.y) * 0.5);
|
||||
float nrm = MAX(bound.x, bound.y);
|
||||
if (nrm > 0) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
handle_positions.write[i] = (handle_positions[i] - center) / nrm * 0.9;
|
||||
sp->set_handle_offset(i, Vector2(0.5 + handle_positions[i].x, 0.5 - handle_positions[i].y));
|
||||
}
|
||||
}
|
||||
|
||||
Error err = ResourceSaver::save(p_file, sp);
|
||||
|
||||
if (err != OK) {
|
||||
EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), p_file));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Variant Skeleton3DEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
|
||||
TreeItem *selected = joint_tree->get_selected();
|
||||
|
||||
@@ -631,6 +703,11 @@ void Skeleton3DEditor::create_editors() {
|
||||
Node3DEditor *ne = Node3DEditor::get_singleton();
|
||||
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
|
||||
|
||||
// Create File dialog.
|
||||
file_dialog = memnew(EditorFileDialog);
|
||||
file_dialog->connect("file_selected", callable_mp(this, &Skeleton3DEditor::_file_selected));
|
||||
add_child(file_dialog);
|
||||
|
||||
// Create Top Menu Bar.
|
||||
separator = memnew(VSeparator);
|
||||
ne->add_control_to_menu_panel(separator);
|
||||
@@ -649,6 +726,7 @@ void Skeleton3DEditor::create_editors() {
|
||||
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/all_poses_to_rests", TTR("Apply all poses to rests")), SKELETON_OPTION_ALL_POSES_TO_RESTS);
|
||||
p->add_shortcut(ED_SHORTCUT("skeleton_3d_editor/selected_poses_to_rests", TTR("Apply selected poses to rests")), SKELETON_OPTION_SELECTED_POSES_TO_RESTS);
|
||||
p->add_item(TTR("Create physical skeleton"), SKELETON_OPTION_CREATE_PHYSICAL_SKELETON);
|
||||
p->add_item(TTR("Export skeleton profile"), SKELETON_OPTION_EXPORT_SKELETON_PROFILE);
|
||||
|
||||
p->connect("id_pressed", callable_mp(this, &Skeleton3DEditor::_on_click_skeleton_option));
|
||||
set_bone_options_enabled(false);
|
||||
|
||||
@@ -101,6 +101,7 @@ class Skeleton3DEditor : public VBoxContainer {
|
||||
SKELETON_OPTION_ALL_POSES_TO_RESTS,
|
||||
SKELETON_OPTION_SELECTED_POSES_TO_RESTS,
|
||||
SKELETON_OPTION_CREATE_PHYSICAL_SKELETON,
|
||||
SKELETON_OPTION_EXPORT_SKELETON_PROFILE,
|
||||
};
|
||||
|
||||
struct BoneInfo {
|
||||
@@ -155,6 +156,8 @@ class Skeleton3DEditor : public VBoxContainer {
|
||||
void create_physical_skeleton();
|
||||
PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);
|
||||
|
||||
void export_skeleton_profile();
|
||||
|
||||
Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
|
||||
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
|
||||
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
|
||||
|
||||
Reference in New Issue
Block a user