summaryrefslogtreecommitdiff
path: root/editor/plugins/skeleton_3d_editor_plugin.h
blob: 3b4dd362fb8a56bc77f51d2c2f47af04c8baf35f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*************************************************************************/
/*  skeleton_3d_editor_plugin.h                                          */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   */
/*                                                                       */
/* 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 SKELETON_3D_EDITOR_PLUGIN_H
#define SKELETON_3D_EDITOR_PLUGIN_H

#include "editor/editor_node.h"
#include "editor/editor_plugin.h"
#include "editor/editor_properties.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/skeleton_3d.h"
#include "scene/resources/immediate_mesh.h"

class EditorInspectorPluginSkeleton;
class Joint;
class PhysicalBone3D;
class Skeleton3DEditorPlugin;
class Button;
class CheckBox;

class BoneTransformEditor : public VBoxContainer {
	GDCLASS(BoneTransformEditor, VBoxContainer);

	EditorInspectorSection *section = nullptr;

	EditorPropertyCheck *enabled_checkbox = nullptr;
	EditorPropertyVector3 *position_property = nullptr;
	EditorPropertyQuaternion *rotation_property = nullptr;
	EditorPropertyVector3 *scale_property = nullptr;

	EditorInspectorSection *rest_section = nullptr;
	EditorPropertyTransform3D *rest_matrix = nullptr;

	Rect2 background_rects[5];

	Skeleton3D *skeleton;
	// String property;

	UndoRedo *undo_redo;

	// Button *key_button = nullptr;

	bool keyable = false;
	bool toggle_enabled = false;
	bool updating = false;

	String label;

	void create_editors();

	void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);

protected:
	void _notification(int p_what);

public:
	BoneTransformEditor(Skeleton3D *p_skeleton);

	// Which transform target to modify.
	void set_target(const String &p_prop);
	void set_label(const String &p_label) { label = p_label; }

	void _update_properties();
};

class Skeleton3DEditor : public VBoxContainer {
	GDCLASS(Skeleton3DEditor, VBoxContainer);

	friend class Skeleton3DEditorPlugin;

	enum SkeletonOption {
		SKELETON_OPTION_INIT_POSE,
		SKELETON_OPTION_INSERT_KEYS,
		SKELETON_OPTION_INSERT_KEYS_EXISTED,
		SKELETON_OPTION_CREATE_PHYSICAL_SKELETON
	};

	enum RestOption {
		REST_OPTION_POSE_TO_REST
	};

	struct BoneInfo {
		PhysicalBone3D *physical_bone = nullptr;
		Transform3D relative_rest; // Relative to skeleton node.
	};

	EditorNode *editor;
	EditorInspectorPluginSkeleton *editor_plugin;

	Skeleton3D *skeleton;

	Tree *joint_tree = nullptr;
	BoneTransformEditor *rest_editor = nullptr;
	BoneTransformEditor *pose_editor = nullptr;

	VSeparator *separator;
	MenuButton *skeleton_options = nullptr;
	MenuButton *rest_options = nullptr;
	Button *edit_mode_button;

	bool edit_mode = false;

	EditorFileDialog *file_dialog = nullptr;

	bool keyable;

	static Skeleton3DEditor *singleton;

	void _on_click_skeleton_option(int p_skeleton_option);
	void _on_click_rest_option(int p_rest_option);
	void _file_selected(const String &p_file);
	TreeItem *_find(TreeItem *p_node, const NodePath &p_path);
	void edit_mode_toggled(const bool pressed);

	EditorFileDialog *file_export_lib = nullptr;

	void update_joint_tree();
	void update_editors();

	void create_editors();

	void init_pose();
	void insert_keys(bool p_all_bones);
	void pose_to_rest();

	void create_physical_skeleton();
	PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector<BoneInfo> &bones_infos);

	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);

	void set_keyable(const bool p_keyable);
	void set_rest_options_enabled(const bool p_rest_options_enabled);

	// Handle.
	MeshInstance3D *handles_mesh_instance;
	Ref<ImmediateMesh> handles_mesh;
	Ref<ShaderMaterial> handle_material;
	Ref<Shader> handle_shader;

	Vector3 bone_original_position;
	Quaternion bone_original_rotation;
	Vector3 bone_original_scale;

	void _update_gizmo_visible();
	void _bone_enabled_changed(const int p_bone_id);

	void _hide_handles();

	void _draw_gizmo();
	void _draw_handles();

	void _joint_tree_selection_changed();
	void _joint_tree_rmb_select(const Vector2 &p_pos);
	void _update_properties();

	void _subgizmo_selection_change();

	int selected_bone = -1;

protected:
	void _notification(int p_what);
	void _node_removed(Node *p_node);
	static void _bind_methods();

public:
	static Skeleton3DEditor *get_singleton() { return singleton; }

	void select_bone(int p_idx);

	int get_selected_bone() const;

	void move_skeleton_bone(NodePath p_skeleton_path, int32_t p_selected_boneidx, int32_t p_target_boneidx);

	Skeleton3D *get_skeleton() const { return skeleton; };

	bool is_edit_mode() const { return edit_mode; }

	void update_bone_original();
	Vector3 get_bone_original_position() const { return bone_original_position; };
	Quaternion get_bone_original_rotation() const { return bone_original_rotation; };
	Vector3 get_bone_original_scale() const { return bone_original_scale; };

	Skeleton3DEditor(EditorInspectorPluginSkeleton *e_plugin, EditorNode *p_editor, Skeleton3D *skeleton);
	~Skeleton3DEditor();
};

class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
	GDCLASS(EditorInspectorPluginSkeleton, EditorInspectorPlugin);

	friend class Skeleton3DEditorPlugin;

	Skeleton3DEditor *skel_editor;
	EditorNode *editor;

public:
	virtual bool can_handle(Object *p_object) override;
	virtual void parse_begin(Object *p_object) override;
};

class Skeleton3DEditorPlugin : public EditorPlugin {
	GDCLASS(Skeleton3DEditorPlugin, EditorPlugin);

	EditorInspectorPluginSkeleton *skeleton_plugin;
	EditorNode *editor;

public:
	virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override;

	bool has_main_screen() const override { return false; }
	virtual bool handles(Object *p_object) const override;

	virtual String get_name() const override { return "Skeleton3D"; }

	Skeleton3DEditorPlugin(EditorNode *p_node);
};

class Skeleton3DGizmoPlugin : public EditorNode3DGizmoPlugin {
	GDCLASS(Skeleton3DGizmoPlugin, EditorNode3DGizmoPlugin);

	Ref<StandardMaterial3D> unselected_mat;
	Ref<ShaderMaterial> selected_mat;
	Ref<Shader> selected_sh;

public:
	bool has_gizmo(Node3D *p_spatial) override;
	String get_gizmo_name() const override;
	int get_priority() const override;

	int subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const override;
	Transform3D get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const override;
	void set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) override;
	void commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) override;

	void redraw(EditorNode3DGizmo *p_gizmo) override;

	Skeleton3DGizmoPlugin();
};

#endif // SKELETON_3D_EDITOR_PLUGIN_H