1/**************************************************************************/
2/* bone_map_editor_plugin.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef BONE_MAP_EDITOR_PLUGIN_H
32#define BONE_MAP_EDITOR_PLUGIN_H
33
34#include "editor/editor_node.h"
35#include "editor/editor_plugin.h"
36#include "editor/editor_properties.h"
37
38#include "modules/modules_enabled.gen.h" // For regex.
39#ifdef MODULE_REGEX_ENABLED
40#include "modules/regex/regex.h"
41#endif
42
43#include "scene/3d/skeleton_3d.h"
44#include "scene/gui/box_container.h"
45#include "scene/gui/color_rect.h"
46#include "scene/gui/dialogs.h"
47#include "scene/resources/bone_map.h"
48#include "scene/resources/texture.h"
49
50class AspectRatioContainer;
51
52class BoneMapperButton : public TextureButton {
53 GDCLASS(BoneMapperButton, TextureButton);
54
55public:
56 enum BoneMapState {
57 BONE_MAP_STATE_UNSET,
58 BONE_MAP_STATE_SET,
59 BONE_MAP_STATE_MISSING,
60 BONE_MAP_STATE_ERROR
61 };
62
63private:
64 StringName profile_bone_name;
65 bool selected = false;
66 bool require = false;
67
68 TextureRect *circle = nullptr;
69
70 void fetch_textures();
71
72protected:
73 void _notification(int p_what);
74
75public:
76 StringName get_profile_bone_name() const;
77 void set_state(BoneMapState p_state);
78
79 bool is_require() const;
80
81 BoneMapperButton(const StringName p_profile_bone_name, bool p_require, bool p_selected);
82 ~BoneMapperButton();
83};
84
85class BoneMapperItem : public VBoxContainer {
86 GDCLASS(BoneMapperItem, VBoxContainer);
87
88 int button_id = -1;
89 StringName profile_bone_name;
90
91 Ref<BoneMap> bone_map;
92
93 EditorPropertyText *skeleton_bone_selector = nullptr;
94 Button *picker_button = nullptr;
95
96 void _update_property();
97 void _open_picker();
98
99protected:
100 void _notification(int p_what);
101 static void _bind_methods();
102 virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
103 virtual void create_editor();
104
105public:
106 void assign_button_id(int p_button_id);
107
108 BoneMapperItem(Ref<BoneMap> &p_bone_map, const StringName &p_profile_bone_name = StringName());
109 ~BoneMapperItem();
110};
111
112class BonePicker : public AcceptDialog {
113 GDCLASS(BonePicker, AcceptDialog);
114
115 Skeleton3D *skeleton = nullptr;
116 Tree *bones = nullptr;
117
118public:
119 void popup_bones_tree(const Size2i &p_minsize = Size2i());
120 bool has_selected_bone();
121 StringName get_selected_bone();
122
123protected:
124 void _notification(int p_what);
125 static void _bind_methods();
126
127 void _confirm();
128
129private:
130 void create_editors();
131 void create_bones_tree(Skeleton3D *p_skeleton);
132
133public:
134 BonePicker(Skeleton3D *p_skeleton);
135 ~BonePicker();
136};
137
138class BoneMapper : public VBoxContainer {
139 GDCLASS(BoneMapper, VBoxContainer);
140
141 Skeleton3D *skeleton = nullptr;
142 Ref<BoneMap> bone_map;
143
144 EditorPropertyResource *profile_selector = nullptr;
145
146 Vector<BoneMapperItem *> bone_mapper_items;
147
148 Button *clear_mapping_button = nullptr;
149
150 VBoxContainer *mapper_item_vbox = nullptr;
151
152 int current_group_idx = 0;
153 int current_bone_idx = -1;
154
155 AspectRatioContainer *bone_mapper_field = nullptr;
156 EditorPropertyEnum *profile_group_selector = nullptr;
157 ColorRect *profile_bg = nullptr;
158 TextureRect *profile_texture = nullptr;
159 Vector<BoneMapperButton *> bone_mapper_buttons;
160
161 void create_editor();
162 void recreate_editor();
163 void clear_items();
164 void recreate_items();
165 void update_group_idx();
166 void _update_state();
167
168 /* Bone picker */
169 BonePicker *picker = nullptr;
170 StringName picker_key_name;
171 void _pick_bone(const StringName &p_bone_name);
172 void _apply_picker_selection();
173 void _clear_mapping_current_group();
174
175#ifdef MODULE_REGEX_ENABLED
176 /* For auto mapping */
177 enum BoneSegregation {
178 BONE_SEGREGATION_NONE,
179 BONE_SEGREGATION_LEFT,
180 BONE_SEGREGATION_RIGHT
181 };
182 int search_bone_by_name(Skeleton3D *p_skeleton, Vector<String> p_picklist, BoneSegregation p_segregation = BONE_SEGREGATION_NONE, int p_parent = -1, int p_child = -1, int p_children_count = -1);
183 BoneSegregation guess_bone_segregation(String p_bone_name);
184 void auto_mapping_process(Ref<BoneMap> &p_bone_map);
185 void _run_auto_mapping();
186#endif // MODULE_REGEX_ENABLED
187
188protected:
189 void _notification(int p_what);
190 static void _bind_methods();
191 virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
192 virtual void _profile_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
193
194public:
195 void set_current_group_idx(int p_group_idx);
196 int get_current_group_idx() const;
197 void set_current_bone_idx(int p_bone_idx);
198 int get_current_bone_idx() const;
199
200 BoneMapper(Skeleton3D *p_skeleton, Ref<BoneMap> &p_bone_map);
201 ~BoneMapper();
202};
203
204class BoneMapEditor : public VBoxContainer {
205 GDCLASS(BoneMapEditor, VBoxContainer);
206
207 Skeleton3D *skeleton = nullptr;
208 Ref<BoneMap> bone_map;
209 BoneMapper *bone_mapper = nullptr;
210
211 void fetch_objects();
212 void create_editors();
213
214protected:
215 void _notification(int p_what);
216
217public:
218 BoneMapEditor(Ref<BoneMap> &p_bone_map);
219 ~BoneMapEditor();
220};
221
222class EditorInspectorPluginBoneMap : public EditorInspectorPlugin {
223 GDCLASS(EditorInspectorPluginBoneMap, EditorInspectorPlugin);
224 BoneMapEditor *editor = nullptr;
225
226public:
227 virtual bool can_handle(Object *p_object) override;
228 virtual void parse_begin(Object *p_object) override;
229};
230
231class BoneMapEditorPlugin : public EditorPlugin {
232 GDCLASS(BoneMapEditorPlugin, EditorPlugin);
233
234public:
235 virtual String get_name() const override { return "BoneMap"; }
236 BoneMapEditorPlugin();
237};
238
239#endif // BONE_MAP_EDITOR_PLUGIN_H
240