Merge pull request #61610 from TokageItLab/importer-retarget-registered-gdhumanoid
|
@ -199,6 +199,21 @@ Vector<StringName> NodePath::get_subnames() const {
|
|||
return Vector<StringName>();
|
||||
}
|
||||
|
||||
StringName NodePath::get_concatenated_names() const {
|
||||
ERR_FAIL_COND_V(!data, StringName());
|
||||
|
||||
if (!data->concatenated_path) {
|
||||
int pc = data->path.size();
|
||||
String concatenated;
|
||||
const StringName *sn = data->path.ptr();
|
||||
for (int i = 0; i < pc; i++) {
|
||||
concatenated += i == 0 ? sn[i].operator String() : "/" + sn[i];
|
||||
}
|
||||
data->concatenated_path = concatenated;
|
||||
}
|
||||
return data->concatenated_path;
|
||||
}
|
||||
|
||||
StringName NodePath::get_concatenated_subnames() const {
|
||||
ERR_FAIL_COND_V(!data, StringName());
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@ class NodePath {
|
|||
SafeRefCount refcount;
|
||||
Vector<StringName> path;
|
||||
Vector<StringName> subpath;
|
||||
StringName concatenated_path;
|
||||
StringName concatenated_subpath;
|
||||
bool absolute;
|
||||
bool has_slashes;
|
||||
|
@ -59,6 +60,7 @@ public:
|
|||
StringName get_subname(int p_idx) const;
|
||||
Vector<StringName> get_names() const;
|
||||
Vector<StringName> get_subnames() const;
|
||||
StringName get_concatenated_names() const;
|
||||
StringName get_concatenated_subnames() const;
|
||||
|
||||
NodePath rel_path_to(const NodePath &p_np) const;
|
||||
|
|
|
@ -1806,6 +1806,7 @@ static void _register_variant_builtin_methods() {
|
|||
bind_method(NodePath, get_subname_count, sarray(), varray());
|
||||
bind_method(NodePath, hash, sarray(), varray());
|
||||
bind_method(NodePath, get_subname, sarray("idx"), varray());
|
||||
bind_method(NodePath, get_concatenated_names, sarray(), varray());
|
||||
bind_method(NodePath, get_concatenated_subnames, sarray(), varray());
|
||||
bind_method(NodePath, get_as_property_path, sarray(), varray());
|
||||
bind_method(NodePath, is_empty, sarray(), varray());
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="BoneMap" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Bone map for retargeting.
|
||||
</brief_description>
|
||||
<description>
|
||||
This class contains a hashmap that uses a list of bone names in [SkeletonProfile] as key names.
|
||||
By assigning the actual [Skeleton3D] bone name as the key value, it maps the [Skeleton3D] to the [SkeletonProfile].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="find_profile_bone_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<argument index="0" name="skeleton_bone_name" type="StringName" />
|
||||
<description>
|
||||
Returns a profile bone name having [code]skeleton_bone_name[/code]. If not found, an empty [StringName] will be returned.
|
||||
In the retargeting process, the returned bone name is the bone name of the target skeleton.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_skeleton_bone_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<argument index="0" name="profile_bone_name" type="StringName" />
|
||||
<description>
|
||||
Returns a skeleton bone name is mapped to [code]profile_bone_name[/code].
|
||||
In the retargeting process, the returned bone name is the bone name of the source skeleton.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_skeleton_bone_name">
|
||||
<return type="void" />
|
||||
<argument index="0" name="profile_bone_name" type="StringName" />
|
||||
<argument index="1" name="skeleton_bone_name" type="StringName" />
|
||||
<description>
|
||||
Maps a skeleton bone name to [code]profile_bone_name[/code].
|
||||
In the retargeting process, the setting bone name is the bone name of the source skeleton.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="profile" type="SkeletonProfile" setter="set_profile" getter="get_profile">
|
||||
A [SkeletonProfile] of the mapping target. Key names in the [BoneMap] are synchronized with it.
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="bone_map_updated">
|
||||
<description>
|
||||
This signal is emitted when change the key value in the [BoneMap]. This is used to validate mapping and to update [BoneMap] editor.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="profile_updated">
|
||||
<description>
|
||||
This signal is emitted when change the value in profile or change the reference of profile. This is used to update key names in the [BoneMap] and to redraw the [BoneMap] editor.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
</class>
|
|
@ -114,7 +114,9 @@
|
|||
</constant>
|
||||
<constant name="INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE" value="5" enum="InternalImportCategory">
|
||||
</constant>
|
||||
<constant name="INTERNAL_IMPORT_CATEGORY_MAX" value="6" enum="InternalImportCategory">
|
||||
<constant name="INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE" value="6" enum="InternalImportCategory">
|
||||
</constant>
|
||||
<constant name="INTERNAL_IMPORT_CATEGORY_MAX" value="7" enum="InternalImportCategory">
|
||||
</constant>
|
||||
</constants>
|
||||
</class>
|
||||
|
|
|
@ -87,6 +87,12 @@
|
|||
[/codeblocks]
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_concatenated_names" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<description>
|
||||
Returns all paths concatenated with a slash character ([code]/[/code]) as separator without subnames.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_concatenated_subnames" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<description>
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="SkeletonProfile" inherits="Resource" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
Profile of a virtual skeleton used as a target for retargeting.
|
||||
</brief_description>
|
||||
<description>
|
||||
This resource is used in [EditorScenePostImport]. Some parameters are referring to bones in [Skeleton3D], [Skin], [Animation], and some other nodes are rewritten based on the parameters of [SkeletonProfile].
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="get_bone_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<description>
|
||||
Returns the name of the bone at [code]bone_idx[/code] that will be the key name in the [BoneMap].
|
||||
In the retargeting process, the returned bone name is the bone name of the target skeleton.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_group" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<description>
|
||||
Returns the group of the bone at [code]bone_idx[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_group_name" qualifiers="const">
|
||||
<return type="StringName" />
|
||||
<argument index="0" name="group_idx" type="int" />
|
||||
<description>
|
||||
Returns the name of the group at [code]group_idx[/code] that will be the drawing group in the [BoneMap] editor.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_handle_offset" qualifiers="const">
|
||||
<return type="Vector2" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<description>
|
||||
Returns the offset of the bone at [code]bone_idx[/code] that will be the button position in the [BoneMap] editor.
|
||||
This is the offset with origin at the top left corner of the square.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_texture" qualifiers="const">
|
||||
<return type="Texture2D" />
|
||||
<argument index="0" name="group_idx" type="int" />
|
||||
<description>
|
||||
Returns the texture of the group at [code]group_idx[/code] that will be the drawing group background image in the [BoneMap] editor.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_bone_name">
|
||||
<return type="void" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<argument index="1" name="bone_name" type="StringName" />
|
||||
<description>
|
||||
Sets the name of the bone at [code]bone_idx[/code] that will be the key name in the [BoneMap].
|
||||
In the retargeting process, the setting bone name is the bone name of the target skeleton.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_group">
|
||||
<return type="void" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<argument index="1" name="group" type="StringName" />
|
||||
<description>
|
||||
Sets the group of the bone at [code]bone_idx[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_group_name">
|
||||
<return type="void" />
|
||||
<argument index="0" name="group_idx" type="int" />
|
||||
<argument index="1" name="group_name" type="StringName" />
|
||||
<description>
|
||||
Sets the name of the group at [code]group_idx[/code] that will be the drawing group in the [BoneMap] editor.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_handle_offset">
|
||||
<return type="void" />
|
||||
<argument index="0" name="bone_idx" type="int" />
|
||||
<argument index="1" name="handle_offset" type="Vector2" />
|
||||
<description>
|
||||
Sets the offset of the bone at [code]bone_idx[/code] that will be the button position in the [BoneMap] editor.
|
||||
This is the offset with origin at the top left corner of the square.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_texture">
|
||||
<return type="void" />
|
||||
<argument index="0" name="group_idx" type="int" />
|
||||
<argument index="1" name="texture" type="Texture2D" />
|
||||
<description>
|
||||
Sets the texture of the group at [code]group_idx[/code] that will be the drawing group background image in the [BoneMap] editor.
|
||||
</description>
|
||||
</method>
|
||||
</methods>
|
||||
<members>
|
||||
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" default="0">
|
||||
</member>
|
||||
<member name="group_size" type="int" setter="set_group_size" getter="get_group_size" default="0">
|
||||
</member>
|
||||
</members>
|
||||
<signals>
|
||||
<signal name="profile_updated">
|
||||
<description>
|
||||
This signal is emitted when change the value in profile. This is used to update key name in the [BoneMap] and to redraw the [BoneMap] editor.
|
||||
[b]Note[/b]: This signal is not connected directly to editor to simplify the reference, instead it is passed on to editor through the [BoneMap].
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
</class>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
|
||||
<brief_description>
|
||||
</brief_description>
|
||||
<description>
|
||||
A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
<members>
|
||||
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" overrides="SkeletonProfile" default="56" />
|
||||
<member name="group_size" type="int" setter="set_group_size" getter="get_group_size" overrides="SkeletonProfile" default="4" />
|
||||
</members>
|
||||
</class>
|
|
@ -134,6 +134,7 @@
|
|||
#include "editor/plugins/audio_stream_editor_plugin.h"
|
||||
#include "editor/plugins/audio_stream_randomizer_editor_plugin.h"
|
||||
#include "editor/plugins/bit_map_editor_plugin.h"
|
||||
#include "editor/plugins/bone_map_editor_plugin.h"
|
||||
#include "editor/plugins/camera_3d_editor_plugin.h"
|
||||
#include "editor/plugins/canvas_item_editor_plugin.h"
|
||||
#include "editor/plugins/collision_polygon_2d_editor_plugin.h"
|
||||
|
@ -7144,6 +7145,7 @@ EditorNode::EditorNode() {
|
|||
add_editor_plugin(memnew(GradientTexture2DEditorPlugin));
|
||||
add_editor_plugin(memnew(BitMapEditorPlugin));
|
||||
add_editor_plugin(memnew(RayCast2DEditorPlugin));
|
||||
add_editor_plugin(memnew(BoneMapEditorPlugin));
|
||||
|
||||
for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) {
|
||||
add_editor_plugin(EditorPlugins::create(i));
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 1024 1024" height="1024" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h1024v1024h-1024z" fill="#3f3f3f"/><path d="m926.5 217.162c-11.5-2-26.03 4.547-37.5 6.5-15.723 2.678-25.238 3.24-33.333 5.167-1.227.292-3.103.763-5.792.958 0 0-.019.16-.052.437-36.819.994-106.823-6.062-138.156-2.062-23.816 3.041-86.334-5.667-105.667-6-13.911-.239-59.292-4.583-71.75-2.5-.667-4.083-1.5-10.75.95-17.468 14.881-7.246 27.229-21.569 35.341-38.467.922 4.424 6.252 4.929 12.459-14.231 5.662-17.478 2.324-22.254-2.313-22.525.172-2.056.279-4.105.313-6.142.788-48.041-15-78.667-69-78.667s-69.787 30.626-69 78.667c.033 2.036.141 4.086.313 6.142-4.637.271-7.975 5.048-2.313 22.525 6.207 19.16 11.537 18.655 12.459 14.231 8.113 16.897 20.461 31.221 35.342 38.467 2.449 6.718 1.617 13.385.949 17.468-12.457-2.083-57.838 2.261-71.75 2.5-19.332.333-81.85 9.041-105.666 6-31.333-4-101.337 3.056-138.156 2.062-.033-.276-.053-.437-.053-.437-2.689-.195-4.564-.666-5.791-.958-8.096-1.927-17.611-2.489-33.334-5.167-11.469-1.953-26-8.5-37.5-6.5-3.367.586 6 9.834 15.5 12.334 13.635 3.588 25.25 10.666 36 13.166-2.25 3.75-15.59 7.063-23 12-5.336 3.557 6.5 6.5 12 5 20.842-5.684 22.973.389 37.514-9.019 30.078 4.078 102.537 20.514 122.154 14.186 12.457-4.018 100.332 7.083 142.332 5.833 6.039-.18 1.656 65.563 2 73.5 3 69-16.842 133.135-18.666 169.667-1.92 38.42-3.42 57.919 7.666 131.333 6.967 46.126-2.521 82.079-2 94 6 137 29 172 4 221-14 27.44 67.449 26.958 65 9-3.012-22.092-12.666-22.333-10.666-46.333 1.896-22.768 16.049-151.298 8.666-206.667-2-15 0-26 2-66 2.355-47.101 7-88 14-123 7 35 11.645 75.899 14 123 2 40 4 51 2 66-7.383 55.369 6.77 183.899 8.667 206.667 2 24-7.654 24.241-10.667 46.333-2.449 17.958 79 18.44 65-9-25-49-2-84 4-221 .522-11.921-8.966-47.874-2-94 11.086-73.414 9.586-92.913 7.667-131.333-1.824-36.532-21.667-100.667-18.667-169.667.345-7.938-4.039-73.68 2-73.5 42 1.25 129.876-9.852 142.333-5.833 19.616 6.328 92.076-10.107 122.153-14.186 14.541 9.407 16.673 3.335 37.514 9.019 5.5 1.5 17.336-1.443 12-5-7.409-4.937-20.75-8.25-23-12 10.75-2.5 22.366-9.578 36.001-13.166 9.5-2.5 18.866-11.748 15.499-12.334z" fill="#b2b2b2"/></svg>
|
After Width: | Height: | Size: 2.1 KiB |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 1024 1024" height="1024" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h1024v1024h-1024z" fill="#3f3f3f"/><path d="m788.105 552.967c17.995-57.892 31.896-124.566 30.875-198.071-3.758-270.403-249.846-251.479-295.568-244.947-359.868 51.409-219.047 452.358-220.453 496.426-4.899 153.499 83.686 170.991 161.665 215.554 2.646 1.512 7.259 1.786 13.313 1.111 7.223 25.179 11.762 59.035 9.548 75.638-3.266 24.495 209.021 24.495 209.021 0 0-62.883 12.233-124.363 33.827-188.89 7.143-2.284 16.054-7.601 25.963-16.95 13.681-12.908 34.839-21.774 45.726-63.145 15.615-59.338 3.869-76.074-13.917-76.726z" fill="#b2b2b2"/></svg>
|
After Width: | Height: | Size: 684 B |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 1024 1024" height="1024" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h1024v1024h-1024z" fill="#3f3f3f"/><path d="m703.906 786.098c7.046-66.929 28.135-153.363 18.529-260.192-1.143-12.71-4.5-48.282-4.46-82.732.025-21.174-2.111-48.505-1.975-64.174.167-19.333-.428-41.584-.625-55.755-1.052-75.44-13.225-85.827-30.813-85.827-17.246 0-26.77 14.266-27.062 84.582-.061 14.42.5 51 .5 58.5 0 17.508-.333 34.167 0 53.5.447 25.955-4.279 68-9 68-3.902 0-8.099-39.299-9.575-76.999-.756-19.326-3.219-58.336-2.6-70.102 1.759-33.413.474-58.914 1.537-90.165 3.183-93.607-13.016-111.729-34.695-111.729-21.973 0-35.979 57.688-34.849 114.224.128 6.394-1.165 50.739.188 89.859.754 21.811-1.07 49.627-1.683 69.67-1.095 35.768-5.755 63.896-8.869 63.896-2.641 0-4.135-32.584-5.456-65.706-.859-21.557-4.468-58.477-3.664-83.616 1.886-59.012-1.139-110.226-1.063-121.501.635-94.955-14.66-123.101-36.052-123.101-21.476 0-37.188 30.192-36.6 123.343.067 10.53-2.62 99.926-1.759 121.816.865 21.992-2.773 65.062-3.517 84.818-1.299 34.521-6.49 63.947-9.124 63.947-3.281 0-10.794-25.638-11.724-60.965-.587-22.275 1.231-50.99.624-70.688-1.257-40.707-3.175-64.631-3.877-99.708-1.945-97.182-16.352-106.289-38.142-106.289-17.957 0-32.453 28.673-32.657 115.03-.065 27.702-2.429 62.626-.315 94.329.805 12.081-.622 42.512-1.875 73.894-.799 20.007-1.102 47.501-1.137 63.775-.17 78.595-26.712 133.424-36.555 131.308-30.333-6.521-51.648-43.918-71.219-117.307-10.551-39.566-36.667-71.149-69.9-77.813-25.9-5.193-19.783 46.161-1.319 125.293 8.65 37.068 27.909 86.227 39.566 122.655 31.653 98.917 125.574 188.563 160.903 228.546 17.146 19.403 236.894 19.403 264.59 0 11.525-8.07 43.087-101.557 45.724-126.616z" fill="#b2b2b2"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 1024 1024" height="1024" viewBox="0 0 1024 1024" width="1024" xmlns="http://www.w3.org/2000/svg"><path d="m0 0h1024v1024h-1024z" fill="#3f3f3f"/><path d="m320.094 786.098c-7.046-66.929-28.135-153.363-18.529-260.192 1.143-12.71 4.5-48.282 4.46-82.732-.025-21.174 2.111-48.505 1.975-64.174-.167-19.333.428-41.584.625-55.755 1.052-75.44 13.225-85.827 30.813-85.827 17.246 0 26.77 14.266 27.062 84.582.061 14.42-.5 51-.5 58.5 0 17.508.333 34.167 0 53.5-.447 25.955 4.279 68 9 68 3.902 0 8.099-39.299 9.575-76.999.756-19.326 3.219-58.336 2.6-70.102-1.759-33.413-.474-58.914-1.537-90.165-3.183-93.607 13.016-111.729 34.695-111.729 21.973 0 35.979 57.688 34.849 114.224-.128 6.394 1.165 50.739-.188 89.859-.754 21.811 1.07 49.627 1.683 69.67 1.095 35.768 5.755 63.896 8.869 63.896 2.641 0 4.135-32.584 5.456-65.706.859-21.557 4.468-58.477 3.664-83.616-1.886-59.012 1.139-110.226 1.063-121.501-.635-94.955 14.66-123.101 36.052-123.101 21.476 0 37.188 30.192 36.6 123.343-.067 10.53 2.62 99.926 1.759 121.816-.865 21.992 2.773 65.062 3.517 84.818 1.299 34.521 6.49 63.947 9.124 63.947 3.281 0 10.794-25.638 11.724-60.965.587-22.275-1.231-50.99-.624-70.688 1.257-40.707 3.176-64.631 3.877-99.708 1.945-97.182 16.352-106.289 38.142-106.289 17.957 0 32.453 28.673 32.657 115.03.065 27.702 2.429 62.626.314 94.329-.805 12.081.622 42.512 1.875 73.894.799 20.007 1.102 47.501 1.137 63.775.171 78.595 26.713 133.424 36.556 131.308 30.333-6.521 51.648-43.918 71.219-117.307 10.551-39.566 36.667-71.149 69.9-77.813 25.9-5.193 19.783 46.161 1.318 125.293-8.649 37.068-27.909 86.227-39.566 122.655-31.652 98.917-125.573 188.563-160.902 228.546-17.146 19.403-236.894 19.403-264.59 0-11.525-8.07-43.087-101.557-45.724-126.616z" fill="#b2b2b2"/></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 12 12" height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill-opacity=".2941" r="5"/><circle cx="6" cy="6" fill="#fff" r="4"/></svg>
|
After Width: | Height: | Size: 215 B |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new 0 0 12 12" height="12" viewBox="0 0 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="6" cy="6" fill="#fff" r="3"/></svg>
|
After Width: | Height: | Size: 165 B |
|
@ -0,0 +1 @@
|
|||
<svg enable-background="new -506.5 517.5 12 12" height="12" viewBox="-506.5 517.5 12 12" width="12" xmlns="http://www.w3.org/2000/svg"><circle cx="-500.5" cy="523.5" fill-opacity=".2941" r="5"/><g fill="#fff"><circle cx="-500.5" cy="523.5" r="4"/><path d="m-499.5 517.5h5v5h-1v-4h-4z"/><path d="m-494.5 524.5v5h-5v-1h4v-4z"/><path d="m-501.5 529.5h-5v-5h1v4h4z"/><path d="m-506.5 522.5v-5h5v1h-4v4z"/></g></svg>
|
After Width: | Height: | Size: 412 B |
|
@ -0,0 +1,144 @@
|
|||
/*************************************************************************/
|
||||
/* post_import_plugin_skeleton_renamer.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "post_import_plugin_skeleton_renamer.h"
|
||||
|
||||
#include "editor/import/scene_import_settings.h"
|
||||
#include "scene/3d/importer_mesh_instance_3d.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/animation/animation_player.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
|
||||
void PostImportPluginSkeletonRenamer::get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) {
|
||||
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
|
||||
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "retarget/bone_renamer/rename_bones"), true));
|
||||
}
|
||||
}
|
||||
|
||||
void PostImportPluginSkeletonRenamer::internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) {
|
||||
if (p_category == INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE) {
|
||||
// Prepare objects.
|
||||
Object *map = p_options["retarget/bone_map"].get_validated_object();
|
||||
if (!map || !bool(p_options["retarget/bone_renamer/rename_bones"])) {
|
||||
return;
|
||||
}
|
||||
BoneMap *bone_map = Object::cast_to<BoneMap>(map);
|
||||
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node);
|
||||
|
||||
// Rename bones in Skeleton3D.
|
||||
{
|
||||
int len = skeleton->get_bone_count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
StringName bn = bone_map->find_profile_bone_name(skeleton->get_bone_name(i));
|
||||
if (bn) {
|
||||
skeleton->set_bone_name(i, bn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename bones in Skin.
|
||||
{
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*", "ImporterMeshInstance3D");
|
||||
while (nodes.size()) {
|
||||
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(nodes.pop_back());
|
||||
Ref<Skin> skin = mi->get_skin();
|
||||
if (skin.is_valid()) {
|
||||
Node *node = mi->get_node(mi->get_skeleton_path());
|
||||
if (node) {
|
||||
Skeleton3D *mesh_skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
if (mesh_skeleton && node == skeleton) {
|
||||
int len = skin->get_bind_count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
StringName bn = bone_map->find_profile_bone_name(skin->get_bind_name(i));
|
||||
if (bn) {
|
||||
skin->set_bind_name(i, bn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename bones in AnimationPlayer.
|
||||
{
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*", "AnimationPlayer");
|
||||
while (nodes.size()) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(nodes.pop_back());
|
||||
List<StringName> anims;
|
||||
ap->get_animation_list(&anims);
|
||||
for (const StringName &name : anims) {
|
||||
Ref<Animation> anim = ap->get_animation(name);
|
||||
int len = anim->get_track_count();
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (anim->track_get_path(i).get_subname_count() != 1 || !(anim->track_get_type(i) == Animation::TYPE_POSITION_3D || anim->track_get_type(i) == Animation::TYPE_ROTATION_3D || anim->track_get_type(i) == Animation::TYPE_SCALE_3D)) {
|
||||
continue;
|
||||
}
|
||||
String track_path = String(anim->track_get_path(i).get_concatenated_names());
|
||||
Node *node = (ap->get_node(ap->get_root()))->get_node(NodePath(track_path));
|
||||
if (node) {
|
||||
Skeleton3D *track_skeleton = Object::cast_to<Skeleton3D>(node);
|
||||
if (track_skeleton && track_skeleton == skeleton) {
|
||||
StringName bn = bone_map->find_profile_bone_name(anim->track_get_path(i).get_subname(0));
|
||||
if (bn) {
|
||||
anim->track_set_path(i, track_path + ":" + bn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rename bones in all Nodes by calling method.
|
||||
{
|
||||
Vector<Variant> vargs;
|
||||
vargs.push_back(p_base_scene);
|
||||
vargs.push_back(skeleton);
|
||||
vargs.push_back(bone_map);
|
||||
const Variant **argptrs = (const Variant **)alloca(sizeof(const Variant **) * vargs.size());
|
||||
const Variant *args = vargs.ptr();
|
||||
uint32_t argcount = vargs.size();
|
||||
for (uint32_t i = 0; i < argcount; i++) {
|
||||
argptrs[i] = &args[i];
|
||||
}
|
||||
|
||||
TypedArray<Node> nodes = p_base_scene->find_children("*");
|
||||
while (nodes.size()) {
|
||||
Node *nd = Object::cast_to<Node>(nodes.pop_back());
|
||||
Callable::CallError ce;
|
||||
nd->callp("_notify_skeleton_bones_renamed", argptrs, argcount, ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PostImportPluginSkeletonRenamer::PostImportPluginSkeletonRenamer() {
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*************************************************************************/
|
||||
/* post_import_plugin_skeleton_renamer.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 POST_IMPORT_PLUGIN_SKELETON_RENAMER_H
|
||||
#define POST_IMPORT_PLUGIN_SKELETON_RENAMER_H
|
||||
|
||||
#include "resource_importer_scene.h"
|
||||
|
||||
class PostImportPluginSkeletonRenamer : public EditorScenePostImportPlugin {
|
||||
GDCLASS(PostImportPluginSkeletonRenamer, EditorScenePostImportPlugin);
|
||||
|
||||
public:
|
||||
virtual void get_internal_import_options(InternalImportCategory p_category, List<ResourceImporter::ImportOption> *r_options) override;
|
||||
virtual void internal_process(InternalImportCategory p_category, Node *p_base_scene, Node *p_node, Ref<Resource> p_resource, const Dictionary &p_options) override;
|
||||
|
||||
PostImportPluginSkeletonRenamer();
|
||||
};
|
||||
|
||||
#endif // POST_IMPORT_PLUGIN_SKELETON_RENAMER_H
|
|
@ -232,6 +232,7 @@ void EditorScenePostImportPlugin::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MATERIAL);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_ANIMATION);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE);
|
||||
BIND_ENUM_CONSTANT(INTERNAL_IMPORT_CATEGORY_MAX);
|
||||
}
|
||||
|
||||
|
@ -765,6 +766,27 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
{
|
||||
//make sure this is unique
|
||||
node_settings = node_settings.duplicate(true);
|
||||
//fill node settings for this node with default values
|
||||
List<ImportOption> iopts;
|
||||
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE, &iopts);
|
||||
} else if (Object::cast_to<AnimationPlayer>(p_node)) {
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
|
||||
} else if (Object::cast_to<Skeleton3D>(p_node)) {
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, &iopts);
|
||||
} else {
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_NODE, &iopts);
|
||||
}
|
||||
for (const ImportOption &E : iopts) {
|
||||
if (!node_settings.has(E.option.name)) {
|
||||
node_settings[E.option.name] = E.default_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ObjectID node_id = p_node->get_instance_id();
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
|
@ -785,6 +807,16 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
}
|
||||
}
|
||||
|
||||
if (Object::cast_to<Skeleton3D>(p_node)) {
|
||||
ObjectID node_id = p_node->get_instance_id();
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, p_root, p_node, Ref<Resource>(), node_settings);
|
||||
if (ObjectDB::get_instance(node_id) == nullptr) { //may have been erased, so do not continue
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object::cast_to<ImporterMeshInstance3D>(p_node)) {
|
||||
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(p_node);
|
||||
|
||||
|
@ -799,6 +831,16 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
|
||||
if (!mat_id.is_empty() && p_material_data.has(mat_id)) {
|
||||
Dictionary matdata = p_material_data[mat_id];
|
||||
{
|
||||
//fill node settings for this node with default values
|
||||
List<ImportOption> iopts;
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MATERIAL, &iopts);
|
||||
for (const ImportOption &E : iopts) {
|
||||
if (!matdata.has(E.option.name)) {
|
||||
matdata[E.option.name] = E.default_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int j = 0; j < post_importer_plugins.size(); j++) {
|
||||
post_importer_plugins.write[j]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MATERIAL, p_root, p_node, mat, matdata);
|
||||
|
@ -966,19 +1008,6 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap<
|
|||
if (Object::cast_to<AnimationPlayer>(p_node)) {
|
||||
AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(p_node);
|
||||
|
||||
{
|
||||
//make sure this is unique
|
||||
node_settings = node_settings.duplicate(true);
|
||||
//fill node settings for this node with default values
|
||||
List<ImportOption> iopts;
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, &iopts);
|
||||
for (const ImportOption &E : iopts) {
|
||||
if (!node_settings.has(E.option.name)) {
|
||||
node_settings[E.option.name] = E.default_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < post_importer_plugins.size(); i++) {
|
||||
post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE, p_root, p_node, Ref<Resource>(), node_settings);
|
||||
}
|
||||
|
@ -1385,6 +1414,10 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
|
|||
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
|
||||
}
|
||||
} 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, "retarget/bone_map", PROPERTY_HINT_RESOURCE_TYPE, "BoneMap", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant()));
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
@ -1499,6 +1532,12 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor
|
|||
}
|
||||
}
|
||||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
|
||||
const bool use_retarget = p_options["retarget/bone_map"].get_validated_object() != nullptr;
|
||||
if (p_option != "retarget/bone_map" && p_option.begins_with("retarget/")) {
|
||||
return use_retarget;
|
||||
}
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
@ -1534,6 +1573,8 @@ bool ResourceImporterScene::get_internal_option_update_view_required(InternalImp
|
|||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE: {
|
||||
} break;
|
||||
case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: {
|
||||
} break;
|
||||
default: {
|
||||
}
|
||||
}
|
||||
|
@ -1622,6 +1663,16 @@ void ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_m
|
|||
|
||||
if (!mesh_id.is_empty() && p_mesh_data.has(mesh_id)) {
|
||||
Dictionary mesh_settings = p_mesh_data[mesh_id];
|
||||
{
|
||||
//fill node settings for this node with default values
|
||||
List<ImportOption> iopts;
|
||||
get_internal_import_options(INTERNAL_IMPORT_CATEGORY_MESH, &iopts);
|
||||
for (const ImportOption &E : iopts) {
|
||||
if (!mesh_settings.has(E.option.name)) {
|
||||
mesh_settings[E.option.name] = E.default_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mesh_settings.has("generate/shadow_meshes")) {
|
||||
int shadow_meshes = mesh_settings["generate/shadow_meshes"];
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
INTERNAL_IMPORT_CATEGORY_MATERIAL,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_MAX
|
||||
};
|
||||
|
||||
|
@ -259,6 +260,7 @@ public:
|
|||
INTERNAL_IMPORT_CATEGORY_MATERIAL = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MATERIAL,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION,
|
||||
INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE,
|
||||
INTERNAL_IMPORT_CATEGORY_MAX = EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -339,6 +339,8 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) {
|
|||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MESH_3D_NODE;
|
||||
} else if (Object::cast_to<AnimationPlayer>(p_node)) {
|
||||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
|
||||
} else if (Object::cast_to<Skeleton3D>(p_node)) {
|
||||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
|
||||
} else {
|
||||
category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
|
||||
}
|
||||
|
@ -617,6 +619,13 @@ SceneImportSettings *SceneImportSettings::get_singleton() {
|
|||
return singleton;
|
||||
}
|
||||
|
||||
Node *SceneImportSettings::get_selected_node() {
|
||||
if (selected_id == "") {
|
||||
return nullptr;
|
||||
}
|
||||
return node_map[selected_id].node;
|
||||
}
|
||||
|
||||
void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
|
||||
selecting = true;
|
||||
scene_import_settings_data->hide_options = false;
|
||||
|
@ -657,6 +666,8 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
|
|||
scene_import_settings_data->hide_options = editing_animation;
|
||||
} else if (Object::cast_to<AnimationPlayer>(nd.node)) {
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_ANIMATION_NODE;
|
||||
} else if (Object::cast_to<Skeleton3D>(nd.node)) {
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE;
|
||||
} else {
|
||||
scene_import_settings_data->category = ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_NODE;
|
||||
scene_import_settings_data->hide_options = editing_animation;
|
||||
|
|
|
@ -201,6 +201,7 @@ public:
|
|||
void update_view();
|
||||
void open_settings(const String &p_path, bool p_for_animation = false);
|
||||
static SceneImportSettings *get_singleton();
|
||||
Node *get_selected_node();
|
||||
SceneImportSettings();
|
||||
~SceneImportSettings();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,439 @@
|
|||
/*************************************************************************/
|
||||
/* bone_map_editor_plugin.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "bone_map_editor_plugin.h"
|
||||
|
||||
#include "editor/editor_scale.h"
|
||||
#include "editor/import/post_import_plugin_skeleton_renamer.h"
|
||||
#include "editor/import/scene_import_settings.h"
|
||||
|
||||
void BoneMapperButton::fetch_textures() {
|
||||
if (selected) {
|
||||
set_normal_texture(get_theme_icon(SNAME("BoneMapperHandleSelected"), SNAME("EditorIcons")));
|
||||
} else {
|
||||
set_normal_texture(get_theme_icon(SNAME("BoneMapperHandle"), SNAME("EditorIcons")));
|
||||
}
|
||||
set_offset(SIDE_LEFT, 0);
|
||||
set_offset(SIDE_RIGHT, 0);
|
||||
set_offset(SIDE_TOP, 0);
|
||||
set_offset(SIDE_BOTTOM, 0);
|
||||
|
||||
circle = memnew(TextureRect);
|
||||
circle->set_texture(get_theme_icon(SNAME("BoneMapperHandleCircle"), SNAME("EditorIcons")));
|
||||
add_child(circle);
|
||||
set_state(BONE_MAP_STATE_UNSET);
|
||||
}
|
||||
|
||||
StringName BoneMapperButton::get_profile_bone_name() const {
|
||||
return profile_bone_name;
|
||||
}
|
||||
|
||||
void BoneMapperButton::set_state(BoneMapState p_state) {
|
||||
switch (p_state) {
|
||||
case BONE_MAP_STATE_UNSET: {
|
||||
circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/unset"));
|
||||
} break;
|
||||
case BONE_MAP_STATE_SET: {
|
||||
circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/set"));
|
||||
} break;
|
||||
case BONE_MAP_STATE_ERROR: {
|
||||
circle->set_modulate(EditorSettings::get_singleton()->get("editors/bone_mapper/handle_colors/error"));
|
||||
} break;
|
||||
default: {
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapperButton::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
fetch_textures();
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
BoneMapperButton::BoneMapperButton(const StringName p_profile_bone_name, bool p_selected) {
|
||||
profile_bone_name = p_profile_bone_name;
|
||||
selected = p_selected;
|
||||
}
|
||||
|
||||
BoneMapperButton::~BoneMapperButton() {
|
||||
}
|
||||
|
||||
void BoneMapperItem::create_editor() {
|
||||
skeleton_bone_selector = memnew(EditorPropertyTextEnum);
|
||||
skeleton_bone_selector->setup(skeleton_bone_names);
|
||||
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));
|
||||
skeleton_bone_selector->update_property();
|
||||
skeleton_bone_selector->connect("property_changed", callable_mp(this, &BoneMapperItem::_value_changed));
|
||||
add_child(skeleton_bone_selector);
|
||||
}
|
||||
|
||||
void BoneMapperItem::_update_property() {
|
||||
if (skeleton_bone_selector->get_edited_object() && skeleton_bone_selector->get_edited_property()) {
|
||||
skeleton_bone_selector->update_property();
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapperItem::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
|
||||
bone_map->set(p_property, p_value);
|
||||
}
|
||||
|
||||
void BoneMapperItem::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
create_editor();
|
||||
bone_map->connect("bone_map_updated", callable_mp(this, &BoneMapperItem::_update_property));
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
if (!bone_map.is_null() && bone_map->is_connected("bone_map_updated", callable_mp(this, &BoneMapperItem::_update_property))) {
|
||||
bone_map->disconnect("bone_map_updated", callable_mp(this, &BoneMapperItem::_update_property));
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapperItem::_bind_methods() {
|
||||
}
|
||||
|
||||
BoneMapperItem::BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name) {
|
||||
bone_map = p_bone_map;
|
||||
skeleton_bone_names = p_skeleton_bone_names;
|
||||
profile_bone_name = p_profile_bone_name;
|
||||
}
|
||||
|
||||
BoneMapperItem::~BoneMapperItem() {
|
||||
}
|
||||
|
||||
void BoneMapper::create_editor() {
|
||||
profile_group_selector = memnew(EditorPropertyEnum);
|
||||
profile_group_selector->set_label("Group");
|
||||
profile_group_selector->set_selectable(false);
|
||||
profile_group_selector->set_object_and_property(this, "current_group_idx");
|
||||
profile_group_selector->update_property();
|
||||
profile_group_selector->connect("property_changed", callable_mp(this, &BoneMapper::_value_changed));
|
||||
add_child(profile_group_selector);
|
||||
|
||||
bone_mapper_field = memnew(AspectRatioContainer);
|
||||
bone_mapper_field->set_stretch_mode(AspectRatioContainer::STRETCH_FIT);
|
||||
bone_mapper_field->set_custom_minimum_size(Vector2(0, 256.0) * EDSCALE);
|
||||
bone_mapper_field->set_h_size_flags(Control::SIZE_FILL);
|
||||
add_child(bone_mapper_field);
|
||||
|
||||
profile_bg = memnew(ColorRect);
|
||||
profile_bg->set_color(Color(0, 0, 0, 1));
|
||||
profile_bg->set_h_size_flags(Control::SIZE_FILL);
|
||||
profile_bg->set_v_size_flags(Control::SIZE_FILL);
|
||||
bone_mapper_field->add_child(profile_bg);
|
||||
|
||||
profile_texture = memnew(TextureRect);
|
||||
profile_texture->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED);
|
||||
profile_texture->set_ignore_texture_size(true);
|
||||
profile_texture->set_h_size_flags(Control::SIZE_FILL);
|
||||
profile_texture->set_v_size_flags(Control::SIZE_FILL);
|
||||
bone_mapper_field->add_child(profile_texture);
|
||||
|
||||
mapper_item_vbox = memnew(VBoxContainer);
|
||||
add_child(mapper_item_vbox);
|
||||
|
||||
separator = memnew(HSeparator);
|
||||
add_child(separator);
|
||||
|
||||
recreate_items();
|
||||
}
|
||||
|
||||
void BoneMapper::update_group_idx() {
|
||||
if (!bone_map->get_profile().is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PackedStringArray group_names;
|
||||
int len = bone_map->get_profile()->get_group_size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
group_names.push_back(bone_map->get_profile()->get_group_name(i));
|
||||
}
|
||||
if (current_group_idx >= len) {
|
||||
current_group_idx = 0;
|
||||
}
|
||||
if (len > 0) {
|
||||
profile_group_selector->setup(group_names);
|
||||
profile_group_selector->update_property();
|
||||
profile_group_selector->set_read_only(false);
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapper::set_current_group_idx(int p_group_idx) {
|
||||
current_group_idx = p_group_idx;
|
||||
recreate_editor();
|
||||
}
|
||||
|
||||
int BoneMapper::get_current_group_idx() const {
|
||||
return current_group_idx;
|
||||
}
|
||||
|
||||
void BoneMapper::set_current_bone_idx(int p_bone_idx) {
|
||||
current_bone_idx = p_bone_idx;
|
||||
recreate_editor();
|
||||
}
|
||||
|
||||
int BoneMapper::get_current_bone_idx() const {
|
||||
return current_bone_idx;
|
||||
}
|
||||
|
||||
void BoneMapper::recreate_editor() {
|
||||
// Clear buttons.
|
||||
int len = bone_mapper_buttons.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
profile_texture->remove_child(bone_mapper_buttons[i]);
|
||||
memdelete(bone_mapper_buttons[i]);
|
||||
}
|
||||
bone_mapper_buttons.clear();
|
||||
|
||||
// Organize mapper items.
|
||||
len = bone_mapper_items.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
bone_mapper_items[i]->set_visible(current_bone_idx == i);
|
||||
}
|
||||
|
||||
Ref<SkeletonProfile> profile = bone_map->get_profile();
|
||||
if (profile.is_valid()) {
|
||||
SkeletonProfileHumanoid *hmn = Object::cast_to<SkeletonProfileHumanoid>(profile.ptr());
|
||||
if (hmn) {
|
||||
StringName hmn_group_name = profile->get_group_name(current_group_idx);
|
||||
if (hmn_group_name == "Body") {
|
||||
profile_texture->set_texture(get_theme_icon(SNAME("BoneMapHumanBody"), SNAME("EditorIcons")));
|
||||
} else if (hmn_group_name == "Face") {
|
||||
profile_texture->set_texture(get_theme_icon(SNAME("BoneMapHumanFace"), SNAME("EditorIcons")));
|
||||
} else if (hmn_group_name == "LeftHand") {
|
||||
profile_texture->set_texture(get_theme_icon(SNAME("BoneMapHumanLeftHand"), SNAME("EditorIcons")));
|
||||
} else if (hmn_group_name == "RightHand") {
|
||||
profile_texture->set_texture(get_theme_icon(SNAME("BoneMapHumanRightHand"), SNAME("EditorIcons")));
|
||||
}
|
||||
} else {
|
||||
profile_texture->set_texture(profile->get_texture(current_group_idx));
|
||||
}
|
||||
} else {
|
||||
profile_texture->set_texture(Ref<Texture2D>());
|
||||
}
|
||||
|
||||
if (!profile.is_valid()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
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);
|
||||
Vector2 vc = profile->get_handle_offset(i);
|
||||
bone_mapper_buttons.push_back(mb);
|
||||
profile_texture->add_child(mb);
|
||||
mb->set_anchor(SIDE_LEFT, vc.x);
|
||||
mb->set_anchor(SIDE_RIGHT, vc.x);
|
||||
mb->set_anchor(SIDE_TOP, vc.y);
|
||||
mb->set_anchor(SIDE_BOTTOM, vc.y);
|
||||
}
|
||||
}
|
||||
|
||||
_update_state();
|
||||
}
|
||||
|
||||
void BoneMapper::clear_items() {
|
||||
// Clear items.
|
||||
int len = bone_mapper_items.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
mapper_item_vbox->remove_child(bone_mapper_items[i]);
|
||||
memdelete(bone_mapper_items[i]);
|
||||
}
|
||||
bone_mapper_items.clear();
|
||||
}
|
||||
|
||||
void BoneMapper::recreate_items() {
|
||||
clear_items();
|
||||
// Create items by profile.
|
||||
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));
|
||||
}
|
||||
|
||||
len = profile->get_bone_size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
StringName bn = profile->get_bone_name(i);
|
||||
bone_mapper_items.append(memnew(BoneMapperItem(bone_map, skeleton_bone_names, bn)));
|
||||
mapper_item_vbox->add_child(bone_mapper_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
update_group_idx();
|
||||
recreate_editor();
|
||||
}
|
||||
|
||||
void BoneMapper::_update_state() {
|
||||
int len = bone_mapper_buttons.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
StringName sbn = bone_map->get_skeleton_bone_name(bone_mapper_buttons[i]->get_profile_bone_name());
|
||||
if (skeleton->find_bone(sbn) >= 0) {
|
||||
if (bone_map->get_skeleton_bone_name_count(sbn) == 1) {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_SET);
|
||||
} else {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_ERROR);
|
||||
}
|
||||
} else {
|
||||
bone_mapper_buttons[i]->set_state(BoneMapperButton::BONE_MAP_STATE_UNSET);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapper::_value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing) {
|
||||
set(p_property, p_value);
|
||||
recreate_editor();
|
||||
}
|
||||
|
||||
void BoneMapper::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_current_group_idx", "current_group_idx"), &BoneMapper::set_current_group_idx);
|
||||
ClassDB::bind_method(D_METHOD("get_current_group_idx"), &BoneMapper::get_current_group_idx);
|
||||
ClassDB::bind_method(D_METHOD("set_current_bone_idx", "current_bone_idx"), &BoneMapper::set_current_bone_idx);
|
||||
ClassDB::bind_method(D_METHOD("get_current_bone_idx"), &BoneMapper::get_current_bone_idx);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_group_idx"), "set_current_group_idx", "get_current_group_idx");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_bone_idx"), "set_current_bone_idx", "get_current_bone_idx");
|
||||
}
|
||||
|
||||
void BoneMapper::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
create_editor();
|
||||
bone_map->connect("bone_map_updated", callable_mp(this, &BoneMapper::_update_state));
|
||||
bone_map->connect("profile_updated", callable_mp(this, &BoneMapper::recreate_items));
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
clear_items();
|
||||
if (!bone_map.is_null()) {
|
||||
if (bone_map->is_connected("bone_map_updated", callable_mp(this, &BoneMapper::_update_state))) {
|
||||
bone_map->disconnect("bone_map_updated", callable_mp(this, &BoneMapper::_update_state));
|
||||
}
|
||||
if (bone_map->is_connected("profile_updated", callable_mp(this, &BoneMapper::recreate_items))) {
|
||||
bone_map->disconnect("profile_updated", callable_mp(this, &BoneMapper::recreate_items));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoneMapper::BoneMapper(Skeleton3D *p_skeleton, Ref<BoneMap> &p_bone_map) {
|
||||
skeleton = p_skeleton;
|
||||
bone_map = p_bone_map;
|
||||
}
|
||||
|
||||
BoneMapper::~BoneMapper() {
|
||||
}
|
||||
|
||||
void BoneMapEditor::create_editors() {
|
||||
if (!skeleton) {
|
||||
return;
|
||||
}
|
||||
bone_mapper = memnew(BoneMapper(skeleton, bone_map));
|
||||
add_child(bone_mapper);
|
||||
}
|
||||
|
||||
void BoneMapEditor::fetch_objects() {
|
||||
// Hackey... but it may be the easist way to get a selected object from "ImporterScene".
|
||||
SceneImportSettings *si = SceneImportSettings::get_singleton();
|
||||
if (!si) {
|
||||
return;
|
||||
}
|
||||
Node *selected = si->get_selected_node();
|
||||
if (selected) {
|
||||
Skeleton3D *sk = Object::cast_to<Skeleton3D>(selected);
|
||||
if (!sk) {
|
||||
return;
|
||||
}
|
||||
skeleton = sk;
|
||||
} else {
|
||||
// Editor should not exist.
|
||||
skeleton = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BoneMapEditor::_notification(int p_what) {
|
||||
switch (p_what) {
|
||||
case NOTIFICATION_ENTER_TREE: {
|
||||
fetch_objects();
|
||||
create_editors();
|
||||
} break;
|
||||
case NOTIFICATION_EXIT_TREE: {
|
||||
remove_child(bone_mapper);
|
||||
bone_mapper->queue_delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BoneMapEditor::BoneMapEditor(Ref<BoneMap> &p_bone_map) {
|
||||
bone_map = p_bone_map;
|
||||
}
|
||||
|
||||
BoneMapEditor::~BoneMapEditor() {
|
||||
}
|
||||
|
||||
bool EditorInspectorPluginBoneMap::can_handle(Object *p_object) {
|
||||
return Object::cast_to<BoneMap>(p_object) != nullptr;
|
||||
}
|
||||
|
||||
void EditorInspectorPluginBoneMap::parse_begin(Object *p_object) {
|
||||
BoneMap *bm = Object::cast_to<BoneMap>(p_object);
|
||||
if (!bm) {
|
||||
return;
|
||||
}
|
||||
Ref<BoneMap> r(bm);
|
||||
editor = memnew(BoneMapEditor(r));
|
||||
add_custom_control(editor);
|
||||
}
|
||||
|
||||
BoneMapEditorPlugin::BoneMapEditorPlugin() {
|
||||
// Register properties in editor settings.
|
||||
EDITOR_DEF("editors/bone_mapper/handle_colors/set", Color(0.1, 0.6, 0.25));
|
||||
EDITOR_DEF("editors/bone_mapper/handle_colors/error", Color(0.8, 0.2, 0.2));
|
||||
EDITOR_DEF("editors/bone_mapper/handle_colors/unset", Color(0.3, 0.3, 0.3));
|
||||
|
||||
Ref<EditorInspectorPluginBoneMap> inspector_plugin;
|
||||
inspector_plugin.instantiate();
|
||||
add_inspector_plugin(inspector_plugin);
|
||||
|
||||
Ref<PostImportPluginSkeletonRenamer> post_import_plugin_renamer;
|
||||
post_import_plugin_renamer.instantiate();
|
||||
add_scene_post_import_plugin(post_import_plugin_renamer);
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
/*************************************************************************/
|
||||
/* bone_map_editor_plugin.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 BONE_MAP_EDITOR_H
|
||||
#define BONE_MAP_EDITOR_H
|
||||
|
||||
#include "editor/editor_node.h"
|
||||
#include "editor/editor_plugin.h"
|
||||
#include "editor/editor_properties.h"
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#include "scene/gui/color_rect.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
class BoneMapperButton : public TextureButton {
|
||||
GDCLASS(BoneMapperButton, TextureButton);
|
||||
|
||||
public:
|
||||
enum BoneMapState {
|
||||
BONE_MAP_STATE_UNSET,
|
||||
BONE_MAP_STATE_SET,
|
||||
BONE_MAP_STATE_ERROR
|
||||
};
|
||||
|
||||
private:
|
||||
StringName profile_bone_name;
|
||||
bool selected = false;
|
||||
|
||||
TextureRect *circle;
|
||||
|
||||
void fetch_textures();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
StringName get_profile_bone_name() const;
|
||||
void set_state(BoneMapState p_state);
|
||||
|
||||
BoneMapperButton(const StringName p_profile_bone_name, bool p_selected);
|
||||
~BoneMapperButton();
|
||||
};
|
||||
|
||||
class BoneMapperItem : public VBoxContainer {
|
||||
GDCLASS(BoneMapperItem, VBoxContainer);
|
||||
|
||||
int button_id = -1;
|
||||
StringName profile_bone_name;
|
||||
|
||||
PackedStringArray skeleton_bone_names;
|
||||
Ref<BoneMap> bone_map;
|
||||
|
||||
EditorPropertyTextEnum *skeleton_bone_selector;
|
||||
|
||||
void _update_property();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
|
||||
virtual void create_editor();
|
||||
|
||||
public:
|
||||
void assign_button_id(int p_button_id);
|
||||
|
||||
BoneMapperItem(Ref<BoneMap> &p_bone_map, PackedStringArray p_skeleton_bone_names, const StringName &p_profile_bone_name = StringName());
|
||||
~BoneMapperItem();
|
||||
};
|
||||
|
||||
class BoneMapper : public VBoxContainer {
|
||||
GDCLASS(BoneMapper, VBoxContainer);
|
||||
|
||||
Skeleton3D *skeleton;
|
||||
Ref<BoneMap> bone_map;
|
||||
|
||||
Vector<BoneMapperItem *> bone_mapper_items;
|
||||
|
||||
VBoxContainer *mapper_item_vbox;
|
||||
HSeparator *separator;
|
||||
|
||||
int current_group_idx = 0;
|
||||
int current_bone_idx = -1;
|
||||
|
||||
AspectRatioContainer *bone_mapper_field;
|
||||
EditorPropertyEnum *profile_group_selector;
|
||||
ColorRect *profile_bg;
|
||||
TextureRect *profile_texture;
|
||||
Vector<BoneMapperButton *> bone_mapper_buttons;
|
||||
|
||||
void create_editor();
|
||||
void recreate_editor();
|
||||
void clear_items();
|
||||
void recreate_items();
|
||||
void update_group_idx();
|
||||
void _update_state();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
virtual void _value_changed(const String &p_property, Variant p_value, const String &p_name, bool p_changing);
|
||||
|
||||
public:
|
||||
void set_current_group_idx(int p_group_idx);
|
||||
int get_current_group_idx() const;
|
||||
void set_current_bone_idx(int p_bone_idx);
|
||||
int get_current_bone_idx() const;
|
||||
|
||||
BoneMapper(Skeleton3D *p_skeleton, Ref<BoneMap> &p_bone_map);
|
||||
~BoneMapper();
|
||||
};
|
||||
|
||||
class BoneMapEditor : public VBoxContainer {
|
||||
GDCLASS(BoneMapEditor, VBoxContainer);
|
||||
|
||||
Skeleton3D *skeleton;
|
||||
Ref<BoneMap> bone_map;
|
||||
BoneMapper *bone_mapper;
|
||||
|
||||
void fetch_objects();
|
||||
void clear_editors();
|
||||
void create_editors();
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
|
||||
public:
|
||||
BoneMapEditor(Ref<BoneMap> &p_bone_map);
|
||||
~BoneMapEditor();
|
||||
};
|
||||
|
||||
class EditorInspectorPluginBoneMap : public EditorInspectorPlugin {
|
||||
GDCLASS(EditorInspectorPluginBoneMap, EditorInspectorPlugin);
|
||||
BoneMapEditor *editor;
|
||||
|
||||
public:
|
||||
virtual bool can_handle(Object *p_object) override;
|
||||
virtual void parse_begin(Object *p_object) override;
|
||||
};
|
||||
|
||||
class BoneMapEditorPlugin : public EditorPlugin {
|
||||
GDCLASS(BoneMapEditorPlugin, EditorPlugin);
|
||||
|
||||
public:
|
||||
virtual String get_name() const override { return "BoneMap"; }
|
||||
BoneMapEditorPlugin();
|
||||
};
|
||||
|
||||
#endif // BONE_MAP_EDITOR_H
|
|
@ -169,6 +169,21 @@ namespace Godot
|
|||
return new NodePath(godot_icall_NodePath_get_as_property_path(GetPtr(this)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all names concatenated with a slash character (<c>/</c>).
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// var nodepath = new NodePath("Path2D/PathFollow2D/Sprite2D:texture:load_path");
|
||||
/// GD.Print(nodepath.GetConcatenatedNames()); // Path2D/PathFollow2D/Sprite2D
|
||||
/// </code>
|
||||
/// </example>
|
||||
/// <returns>The names concatenated with <c>/</c>.</returns>
|
||||
public string GetConcatenatedNames()
|
||||
{
|
||||
return godot_icall_NodePath_get_concatenated_names(GetPtr(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all subnames concatenated with a colon character (<c>:</c>)
|
||||
/// as separator, i.e. the right side of the first colon in a node path.
|
||||
|
@ -268,6 +283,9 @@ namespace Godot
|
|||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern IntPtr godot_icall_NodePath_get_as_property_path(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern string godot_icall_NodePath_get_concatenated_names(IntPtr ptr);
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
private static extern string godot_icall_NodePath_get_concatenated_subnames(IntPtr ptr);
|
||||
|
||||
|
|
|
@ -68,6 +68,10 @@ MonoString *godot_icall_NodePath_get_subname(NodePath *p_ptr, uint32_t p_idx) {
|
|||
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_subname(p_idx));
|
||||
}
|
||||
|
||||
MonoString *godot_icall_NodePath_get_concatenated_names(NodePath *p_ptr) {
|
||||
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_names());
|
||||
}
|
||||
|
||||
MonoString *godot_icall_NodePath_get_concatenated_subnames(NodePath *p_ptr) {
|
||||
return GDMonoMarshal::mono_string_from_godot(p_ptr->get_concatenated_subnames());
|
||||
}
|
||||
|
@ -85,6 +89,7 @@ void godot_register_nodepath_icalls() {
|
|||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_Dtor", godot_icall_NodePath_Dtor);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_operator_String", godot_icall_NodePath_operator_String);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_as_property_path", godot_icall_NodePath_get_as_property_path);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_names", godot_icall_NodePath_get_concatenated_names);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_concatenated_subnames", godot_icall_NodePath_get_concatenated_subnames);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name", godot_icall_NodePath_get_name);
|
||||
GDMonoUtils::add_internal_call("Godot.NodePath::godot_icall_NodePath_get_name_count", godot_icall_NodePath_get_name_count);
|
||||
|
|
|
@ -376,6 +376,24 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) {
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef TOOLS_ENABLED
|
||||
void BoneAttachment3D::_notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Ref<BoneMap> p_bone_map) {
|
||||
const Skeleton3D *parent = nullptr;
|
||||
if (use_external_skeleton) {
|
||||
if (external_skeleton_node_cache.is_valid()) {
|
||||
parent = Object::cast_to<Skeleton3D>(ObjectDB::get_instance(external_skeleton_node_cache));
|
||||
}
|
||||
} else {
|
||||
parent = Object::cast_to<Skeleton3D>(get_parent());
|
||||
}
|
||||
if (parent && parent == p_skeleton) {
|
||||
StringName bn = p_bone_map->find_profile_bone_name(bone_name);
|
||||
if (bn) {
|
||||
set_bone_name(bn);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
BoneAttachment3D::BoneAttachment3D() {
|
||||
}
|
||||
|
@ -398,6 +416,9 @@ void BoneAttachment3D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton);
|
||||
ClassDB::bind_method(D_METHOD("set_external_skeleton", "external_skeleton"), &BoneAttachment3D::set_external_skeleton);
|
||||
ClassDB::bind_method(D_METHOD("get_external_skeleton"), &BoneAttachment3D::get_external_skeleton);
|
||||
#ifdef TOOLS_ENABLED
|
||||
ClassDB::bind_method(D_METHOD("_notify_skeleton_bones_renamed"), &BoneAttachment3D::_notify_skeleton_bones_renamed);
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx");
|
||||
|
|
|
@ -32,6 +32,9 @@
|
|||
#define BONE_ATTACHMENT_H
|
||||
|
||||
#include "scene/3d/skeleton_3d.h"
|
||||
#ifdef TOOLS_ENABLED
|
||||
#include "scene/resources/bone_map.h"
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
class BoneAttachment3D : public Node3D {
|
||||
GDCLASS(BoneAttachment3D, Node3D);
|
||||
|
@ -68,6 +71,9 @@ protected:
|
|||
void _notification(int p_what);
|
||||
|
||||
static void _bind_methods();
|
||||
#ifdef TOOLS_ENABLED
|
||||
virtual void _notify_skeleton_bones_renamed(Node *p_base_scene, Skeleton3D *p_skeleton, Ref<BoneMap> p_bone_map);
|
||||
#endif // TOOLS_ENABLED
|
||||
|
||||
public:
|
||||
virtual TypedArray<String> get_configuration_warnings() const override;
|
||||
|
|
|
@ -143,6 +143,7 @@
|
|||
#include "scene/resources/animation_library.h"
|
||||
#include "scene/resources/audio_stream_sample.h"
|
||||
#include "scene/resources/bit_map.h"
|
||||
#include "scene/resources/bone_map.h"
|
||||
#include "scene/resources/box_shape_3d.h"
|
||||
#include "scene/resources/camera_effects.h"
|
||||
#include "scene/resources/capsule_shape_2d.h"
|
||||
|
@ -189,6 +190,7 @@
|
|||
#include "scene/resources/skeleton_modification_3d_twoboneik.h"
|
||||
#include "scene/resources/skeleton_modification_stack_2d.h"
|
||||
#include "scene/resources/skeleton_modification_stack_3d.h"
|
||||
#include "scene/resources/skeleton_profile.h"
|
||||
#include "scene/resources/sky.h"
|
||||
#include "scene/resources/sky_material.h"
|
||||
#include "scene/resources/sphere_shape_3d.h"
|
||||
|
@ -871,6 +873,10 @@ void register_scene_types() {
|
|||
GDREGISTER_CLASS(BitMap);
|
||||
GDREGISTER_CLASS(Gradient);
|
||||
|
||||
GDREGISTER_CLASS(SkeletonProfile);
|
||||
GDREGISTER_CLASS(SkeletonProfileHumanoid);
|
||||
GDREGISTER_CLASS(BoneMap);
|
||||
|
||||
OS::get_singleton()->yield(); // may take time to init
|
||||
|
||||
GDREGISTER_CLASS(AudioStreamPlayer);
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*************************************************************************/
|
||||
/* bone_map.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "bone_map.h"
|
||||
|
||||
bool BoneMap::_set(const StringName &p_path, const Variant &p_value) {
|
||||
String path = p_path;
|
||||
if (path.begins_with("bone_map/")) {
|
||||
String which = path.get_slicec('/', 1);
|
||||
set_skeleton_bone_name(which, p_value);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BoneMap::_get(const StringName &p_path, Variant &r_ret) const {
|
||||
String path = p_path;
|
||||
if (path.begins_with("bone_map/")) {
|
||||
String which = path.get_slicec('/', 1);
|
||||
r_ret = get_skeleton_bone_name(which);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<SkeletonProfile> BoneMap::get_profile() const {
|
||||
return profile;
|
||||
}
|
||||
|
||||
void BoneMap::set_profile(const Ref<SkeletonProfile> &p_profile) {
|
||||
bool is_changed = profile != p_profile;
|
||||
if (is_changed) {
|
||||
if (!profile.is_null() && profile->is_connected("profile_updated", callable_mp(this, &BoneMap::_update_profile))) {
|
||||
profile->disconnect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
|
||||
}
|
||||
profile = p_profile;
|
||||
if (!profile.is_null()) {
|
||||
profile->connect("profile_updated", callable_mp(this, &BoneMap::_update_profile));
|
||||
}
|
||||
_update_profile();
|
||||
}
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
StringName BoneMap::get_skeleton_bone_name(StringName p_profile_bone_name) const {
|
||||
ERR_FAIL_COND_V(!bone_map.has(p_profile_bone_name), StringName());
|
||||
return bone_map.get(p_profile_bone_name);
|
||||
}
|
||||
|
||||
void BoneMap::set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name) {
|
||||
ERR_FAIL_COND(!bone_map.has(p_profile_bone_name));
|
||||
bone_map.insert(p_profile_bone_name, p_skeleton_bone_name);
|
||||
emit_signal("bone_map_updated");
|
||||
}
|
||||
|
||||
StringName BoneMap::find_profile_bone_name(StringName p_skeleton_bone_name) const {
|
||||
StringName profile_bone_name = StringName();
|
||||
HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
|
||||
while (E) {
|
||||
if (E->value == p_skeleton_bone_name) {
|
||||
profile_bone_name = E->key;
|
||||
break;
|
||||
}
|
||||
++E;
|
||||
}
|
||||
return profile_bone_name;
|
||||
}
|
||||
|
||||
int BoneMap::get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const {
|
||||
int count = 0;
|
||||
HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
|
||||
while (E) {
|
||||
if (E->value == p_skeleton_bone_name) {
|
||||
++count;
|
||||
}
|
||||
++E;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
void BoneMap::_update_profile() {
|
||||
_validate_bone_map();
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
void BoneMap::_validate_bone_map() {
|
||||
Ref<SkeletonProfile> current_profile = get_profile();
|
||||
if (current_profile.is_valid()) {
|
||||
// Insert missing profile bones into bone map.
|
||||
int len = current_profile->get_bone_size();
|
||||
StringName profile_bone_name;
|
||||
for (int i = 0; i < len; i++) {
|
||||
profile_bone_name = current_profile->get_bone_name(i);
|
||||
if (!bone_map.has(profile_bone_name)) {
|
||||
bone_map.insert(profile_bone_name, StringName());
|
||||
}
|
||||
}
|
||||
// Remove bones that do not exist in the profile from the map.
|
||||
Vector<StringName> delete_bones;
|
||||
StringName k;
|
||||
HashMap<StringName, StringName>::ConstIterator E = bone_map.begin();
|
||||
while (E) {
|
||||
k = E->key;
|
||||
if (!current_profile->has_bone(k)) {
|
||||
delete_bones.push_back(k);
|
||||
}
|
||||
++E;
|
||||
}
|
||||
len = delete_bones.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
bone_map.erase(delete_bones[i]);
|
||||
}
|
||||
} else {
|
||||
bone_map.clear();
|
||||
}
|
||||
emit_signal("retarget_option_updated");
|
||||
}
|
||||
|
||||
void BoneMap::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_profile"), &BoneMap::get_profile);
|
||||
ClassDB::bind_method(D_METHOD("set_profile", "profile"), &BoneMap::set_profile);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_skeleton_bone_name", "profile_bone_name"), &BoneMap::get_skeleton_bone_name);
|
||||
ClassDB::bind_method(D_METHOD("set_skeleton_bone_name", "profile_bone_name", "skeleton_bone_name"), &BoneMap::set_skeleton_bone_name);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("find_profile_bone_name", "skeleton_bone_name"), &BoneMap::find_profile_bone_name);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "profile", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonProfile"), "set_profile", "get_profile");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("bone_map_updated"));
|
||||
ADD_SIGNAL(MethodInfo("profile_updated"));
|
||||
}
|
||||
|
||||
void BoneMap::_validate_property(PropertyInfo &property) const {
|
||||
//
|
||||
}
|
||||
|
||||
BoneMap::BoneMap() {
|
||||
_validate_bone_map();
|
||||
}
|
||||
|
||||
BoneMap::~BoneMap() {
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
|
@ -0,0 +1,69 @@
|
|||
/*************************************************************************/
|
||||
/* bone_map.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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 BONE_MAP_H
|
||||
#define BONE_MAP_H
|
||||
|
||||
#include "skeleton_profile.h"
|
||||
|
||||
class BoneMap : public Resource {
|
||||
GDCLASS(BoneMap, Resource);
|
||||
|
||||
Ref<SkeletonProfile> profile;
|
||||
HashMap<StringName, StringName> bone_map;
|
||||
|
||||
void _update_profile();
|
||||
void _validate_bone_map();
|
||||
|
||||
protected:
|
||||
bool _get(const StringName &p_path, Variant &r_ret) const;
|
||||
bool _set(const StringName &p_path, const Variant &p_value);
|
||||
virtual void _validate_property(PropertyInfo &property) const override;
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
int get_profile_type() const;
|
||||
void set_profile_type(const int p_profile_type);
|
||||
|
||||
Ref<SkeletonProfile> get_profile() const;
|
||||
void set_profile(const Ref<SkeletonProfile> &p_profile);
|
||||
|
||||
int get_skeleton_bone_name_count(const StringName p_skeleton_bone_name) const;
|
||||
|
||||
StringName get_skeleton_bone_name(StringName p_profile_bone_name) const;
|
||||
void set_skeleton_bone_name(StringName p_profile_bone_name, const StringName p_skeleton_bone_name);
|
||||
|
||||
StringName find_profile_bone_name(StringName p_skeleton_bone_name) const;
|
||||
|
||||
BoneMap();
|
||||
~BoneMap();
|
||||
};
|
||||
|
||||
#endif // BONE_MAP_H
|
|
@ -0,0 +1,514 @@
|
|||
/*************************************************************************/
|
||||
/* skeleton_profile.cpp */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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. */
|
||||
/*************************************************************************/
|
||||
|
||||
#include "skeleton_profile.h"
|
||||
|
||||
bool SkeletonProfile::_set(const StringName &p_path, const Variant &p_value) {
|
||||
ERR_FAIL_COND_V(is_read_only, false);
|
||||
String path = p_path;
|
||||
|
||||
if (path.begins_with("group/")) {
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
ERR_FAIL_INDEX_V(which, groups.size(), false);
|
||||
|
||||
if (what == "group_name") {
|
||||
set_group_name(which, p_value);
|
||||
} else if (what == "texture") {
|
||||
set_texture(which, p_value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (path.begins_with("bone/")) {
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
ERR_FAIL_INDEX_V(which, bones.size(), false);
|
||||
|
||||
if (what == "bone_name") {
|
||||
set_bone_name(which, p_value);
|
||||
} else if (what == "handle_offset") {
|
||||
set_handle_offset(which, p_value);
|
||||
} else if (what == "group") {
|
||||
set_group(which, p_value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SkeletonProfile::_get(const StringName &p_path, Variant &r_ret) const {
|
||||
String path = p_path;
|
||||
|
||||
if (path.begins_with("group/")) {
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
ERR_FAIL_INDEX_V(which, groups.size(), false);
|
||||
|
||||
if (what == "group_name") {
|
||||
r_ret = get_group_name(which);
|
||||
} else if (what == "texture") {
|
||||
r_ret = get_texture(which);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (path.begins_with("bone/")) {
|
||||
int which = path.get_slicec('/', 1).to_int();
|
||||
String what = path.get_slicec('/', 2);
|
||||
ERR_FAIL_INDEX_V(which, bones.size(), false);
|
||||
|
||||
if (what == "bone_name") {
|
||||
r_ret = get_bone_name(which);
|
||||
} else if (what == "handle_offset") {
|
||||
r_ret = get_handle_offset(which);
|
||||
} else if (what == "group") {
|
||||
r_ret = get_group(which);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SkeletonProfile::_validate_property(PropertyInfo &property) const {
|
||||
if (is_read_only) {
|
||||
if (property.name == ("group_size") || property.name == ("bone_size")) {
|
||||
property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonProfile::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
String group_names = "";
|
||||
for (int i = 0; i < groups.size(); i++) {
|
||||
String path = "group/" + itos(i) + "/";
|
||||
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group_name"));
|
||||
p_list->push_back(PropertyInfo(Variant::OBJECT, path + "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
|
||||
if (i > 0) {
|
||||
group_names = group_names + ",";
|
||||
}
|
||||
group_names = group_names + groups[i].group_name;
|
||||
}
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
String path = "bone/" + itos(i) + "/";
|
||||
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "bone_name"));
|
||||
p_list->push_back(PropertyInfo(Variant::VECTOR2, path + "handle_offset"));
|
||||
p_list->push_back(PropertyInfo(Variant::STRING_NAME, path + "group", PROPERTY_HINT_ENUM, group_names));
|
||||
}
|
||||
}
|
||||
|
||||
int SkeletonProfile::get_group_size() {
|
||||
return groups.size();
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_group_size(int p_size) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_COND(p_size < 0);
|
||||
groups.resize(p_size);
|
||||
emit_signal("profile_updated");
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
StringName SkeletonProfile::get_group_name(int p_group_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_group_idx, groups.size(), StringName());
|
||||
return groups[p_group_idx].group_name;
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_group_name(int p_group_idx, const StringName p_group_name) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_INDEX(p_group_idx, groups.size());
|
||||
groups.write[p_group_idx].group_name = p_group_name;
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
Ref<Texture2D> SkeletonProfile::get_texture(int p_group_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_group_idx, groups.size(), Ref<Texture2D>());
|
||||
return groups[p_group_idx].texture;
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_texture(int p_group_idx, const Ref<Texture2D> &p_texture) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_INDEX(p_group_idx, groups.size());
|
||||
groups.write[p_group_idx].texture = p_texture;
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
int SkeletonProfile::get_bone_size() {
|
||||
return bones.size();
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_bone_size(int p_size) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_COND(p_size < 0);
|
||||
bones.resize(p_size);
|
||||
emit_signal("profile_updated");
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
StringName SkeletonProfile::get_bone_name(int p_bone_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
|
||||
return bones[p_bone_idx].bone_name;
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_bone_name(int p_bone_idx, const StringName p_bone_name) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_INDEX(p_bone_idx, bones.size());
|
||||
bones.write[p_bone_idx].bone_name = p_bone_name;
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
Vector2 SkeletonProfile::get_handle_offset(int p_bone_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), Vector2());
|
||||
return bones[p_bone_idx].handle_offset;
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_INDEX(p_bone_idx, bones.size());
|
||||
bones.write[p_bone_idx].handle_offset = p_handle_offset;
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
StringName SkeletonProfile::get_group(int p_bone_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_bone_idx, bones.size(), StringName());
|
||||
return bones[p_bone_idx].group;
|
||||
}
|
||||
|
||||
void SkeletonProfile::set_group(int p_bone_idx, const StringName p_group) {
|
||||
if (is_read_only) {
|
||||
return;
|
||||
}
|
||||
ERR_FAIL_INDEX(p_bone_idx, bones.size());
|
||||
bones.write[p_bone_idx].group = p_group;
|
||||
emit_signal("profile_updated");
|
||||
}
|
||||
|
||||
bool SkeletonProfile::has_bone(StringName p_bone_name) {
|
||||
bool is_found = false;
|
||||
for (int i = 0; i < bones.size(); i++) {
|
||||
if (bones[i].bone_name == p_bone_name) {
|
||||
is_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return is_found;
|
||||
}
|
||||
|
||||
void SkeletonProfile::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("set_group_size", "size"), &SkeletonProfile::set_group_size);
|
||||
ClassDB::bind_method(D_METHOD("get_group_size"), &SkeletonProfile::get_group_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_group_name", "group_idx"), &SkeletonProfile::get_group_name);
|
||||
ClassDB::bind_method(D_METHOD("set_group_name", "group_idx", "group_name"), &SkeletonProfile::set_group_name);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_texture", "group_idx"), &SkeletonProfile::get_texture);
|
||||
ClassDB::bind_method(D_METHOD("set_texture", "group_idx", "texture"), &SkeletonProfile::set_texture);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_bone_size", "size"), &SkeletonProfile::set_bone_size);
|
||||
ClassDB::bind_method(D_METHOD("get_bone_size"), &SkeletonProfile::get_bone_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_bone_name", "bone_idx"), &SkeletonProfile::get_bone_name);
|
||||
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_idx", "bone_name"), &SkeletonProfile::set_bone_name);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_handle_offset", "bone_idx"), &SkeletonProfile::get_handle_offset);
|
||||
ClassDB::bind_method(D_METHOD("set_handle_offset", "bone_idx", "handle_offset"), &SkeletonProfile::set_handle_offset);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_group", "bone_idx"), &SkeletonProfile::get_group);
|
||||
ClassDB::bind_method(D_METHOD("set_group", "bone_idx", "group"), &SkeletonProfile::set_group);
|
||||
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "group_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Groups,group/"), "set_group_size", "get_group_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_size", PROPERTY_HINT_RANGE, "0,100,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Bones,bone/"), "set_bone_size", "get_bone_size");
|
||||
|
||||
ADD_SIGNAL(MethodInfo("profile_updated"));
|
||||
}
|
||||
|
||||
SkeletonProfile::SkeletonProfile() {
|
||||
}
|
||||
|
||||
SkeletonProfile::~SkeletonProfile() {
|
||||
}
|
||||
|
||||
SkeletonProfileHumanoid::SkeletonProfileHumanoid() {
|
||||
is_read_only = true;
|
||||
|
||||
groups.resize(4);
|
||||
|
||||
groups.write[0].group_name = "Body";
|
||||
groups.write[1].group_name = "Face";
|
||||
groups.write[2].group_name = "LeftHand";
|
||||
groups.write[3].group_name = "RightHand";
|
||||
|
||||
bones.resize(56);
|
||||
|
||||
bones.write[0].bone_name = "Root";
|
||||
bones.write[0].handle_offset = Vector2(0.5, 0.91);
|
||||
bones.write[0].group = "Body";
|
||||
|
||||
bones.write[1].bone_name = "Hips";
|
||||
bones.write[1].handle_offset = Vector2(0.5, 0.5);
|
||||
bones.write[1].group = "Body";
|
||||
|
||||
bones.write[2].bone_name = "Spine";
|
||||
bones.write[2].handle_offset = Vector2(0.5, 0.43);
|
||||
bones.write[2].group = "Body";
|
||||
|
||||
bones.write[3].bone_name = "Chest";
|
||||
bones.write[3].handle_offset = Vector2(0.5, 0.36);
|
||||
bones.write[3].group = "Body";
|
||||
|
||||
bones.write[4].bone_name = "UpperChest";
|
||||
bones.write[4].handle_offset = Vector2(0.5, 0.29);
|
||||
bones.write[4].group = "Body";
|
||||
|
||||
bones.write[5].bone_name = "Neck";
|
||||
bones.write[5].handle_offset = Vector2(0.5, 0.23);
|
||||
bones.write[5].group = "Body";
|
||||
|
||||
bones.write[6].bone_name = "Head";
|
||||
bones.write[6].handle_offset = Vector2(0.5, 0.18);
|
||||
bones.write[6].group = "Body";
|
||||
|
||||
bones.write[7].bone_name = "LeftEye";
|
||||
bones.write[7].handle_offset = Vector2(0.6, 0.46);
|
||||
bones.write[7].group = "Face";
|
||||
|
||||
bones.write[8].bone_name = "RightEye";
|
||||
bones.write[8].handle_offset = Vector2(0.37, 0.46);
|
||||
bones.write[8].group = "Face";
|
||||
|
||||
bones.write[9].bone_name = "Jaw";
|
||||
bones.write[9].handle_offset = Vector2(0.46, 0.75);
|
||||
bones.write[9].group = "Face";
|
||||
|
||||
bones.write[10].bone_name = "LeftShoulder";
|
||||
bones.write[10].handle_offset = Vector2(0.55, 0.235);
|
||||
bones.write[10].group = "Body";
|
||||
|
||||
bones.write[11].bone_name = "LeftUpperArm";
|
||||
bones.write[11].handle_offset = Vector2(0.6, 0.24);
|
||||
bones.write[11].group = "Body";
|
||||
|
||||
bones.write[12].bone_name = "LeftLowerArm";
|
||||
bones.write[12].handle_offset = Vector2(0.7, 0.24);
|
||||
bones.write[12].group = "Body";
|
||||
|
||||
bones.write[13].bone_name = "LeftHand";
|
||||
bones.write[13].handle_offset = Vector2(0.82, 0.235);
|
||||
bones.write[13].group = "Body";
|
||||
|
||||
bones.write[14].bone_name = "LeftThumbProximal";
|
||||
bones.write[14].handle_offset = Vector2(0.4, 0.8);
|
||||
bones.write[14].group = "LeftHand";
|
||||
|
||||
bones.write[15].bone_name = "LeftThumbIntermediate";
|
||||
bones.write[15].handle_offset = Vector2(0.3, 0.69);
|
||||
bones.write[15].group = "LeftHand";
|
||||
|
||||
bones.write[16].bone_name = "LeftThumbDistal";
|
||||
bones.write[16].handle_offset = Vector2(0.23, 0.555);
|
||||
bones.write[16].group = "LeftHand";
|
||||
|
||||
bones.write[17].bone_name = "LeftIndexProximal";
|
||||
bones.write[17].handle_offset = Vector2(0.413, 0.52);
|
||||
bones.write[17].group = "LeftHand";
|
||||
|
||||
bones.write[18].bone_name = "LeftIndexIntermediate";
|
||||
bones.write[18].handle_offset = Vector2(0.403, 0.36);
|
||||
bones.write[18].group = "LeftHand";
|
||||
|
||||
bones.write[19].bone_name = "LeftIndexDistal";
|
||||
bones.write[19].handle_offset = Vector2(0.403, 0.255);
|
||||
bones.write[19].group = "LeftHand";
|
||||
|
||||
bones.write[20].bone_name = "LeftMiddleProximal";
|
||||
bones.write[20].handle_offset = Vector2(0.5, 0.51);
|
||||
bones.write[20].group = "LeftHand";
|
||||
|
||||
bones.write[21].bone_name = "LeftMiddleIntermediate";
|
||||
bones.write[21].handle_offset = Vector2(0.5, 0.345);
|
||||
bones.write[21].group = "LeftHand";
|
||||
|
||||
bones.write[22].bone_name = "LeftMiddleDistal";
|
||||
bones.write[22].handle_offset = Vector2(0.5, 0.22);
|
||||
bones.write[22].group = "LeftHand";
|
||||
|
||||
bones.write[23].bone_name = "LeftRingProximal";
|
||||
bones.write[23].handle_offset = Vector2(0.586, 0.52);
|
||||
bones.write[23].group = "LeftHand";
|
||||
|
||||
bones.write[24].bone_name = "LeftRingIntermediate";
|
||||
bones.write[24].handle_offset = Vector2(0.59, 0.36);
|
||||
bones.write[24].group = "LeftHand";
|
||||
|
||||
bones.write[25].bone_name = "LeftRingDistal";
|
||||
bones.write[25].handle_offset = Vector2(0.591, 0.25);
|
||||
bones.write[25].group = "LeftHand";
|
||||
|
||||
bones.write[26].bone_name = "LeftLittleProximal";
|
||||
bones.write[26].handle_offset = Vector2(0.663, 0.543);
|
||||
bones.write[26].group = "LeftHand";
|
||||
|
||||
bones.write[27].bone_name = "LeftLittleIntermediate";
|
||||
bones.write[27].handle_offset = Vector2(0.672, 0.415);
|
||||
bones.write[27].group = "LeftHand";
|
||||
|
||||
bones.write[28].bone_name = "LeftLittleDistal";
|
||||
bones.write[28].handle_offset = Vector2(0.672, 0.32);
|
||||
bones.write[28].group = "LeftHand";
|
||||
|
||||
bones.write[29].bone_name = "RightShoulder";
|
||||
bones.write[29].handle_offset = Vector2(0.45, 0.235);
|
||||
bones.write[29].group = "Body";
|
||||
|
||||
bones.write[30].bone_name = "RightUpperArm";
|
||||
bones.write[30].handle_offset = Vector2(0.4, 0.24);
|
||||
bones.write[30].group = "Body";
|
||||
|
||||
bones.write[31].bone_name = "RightLowerArm";
|
||||
bones.write[31].handle_offset = Vector2(0.3, 0.24);
|
||||
bones.write[31].group = "Body";
|
||||
|
||||
bones.write[32].bone_name = "RightHand";
|
||||
bones.write[32].handle_offset = Vector2(0.18, 0.235);
|
||||
bones.write[32].group = "Body";
|
||||
|
||||
bones.write[33].bone_name = "RightThumbProximal";
|
||||
bones.write[33].handle_offset = Vector2(0.6, 0.8);
|
||||
bones.write[33].group = "RightHand";
|
||||
|
||||
bones.write[34].bone_name = "RightThumbIntermediate";
|
||||
bones.write[34].handle_offset = Vector2(0.7, 0.69);
|
||||
bones.write[34].group = "RightHand";
|
||||
|
||||
bones.write[35].bone_name = "RightThumbDistal";
|
||||
bones.write[35].handle_offset = Vector2(0.77, 0.555);
|
||||
bones.write[35].group = "RightHand";
|
||||
|
||||
bones.write[36].bone_name = "RightIndexProximal";
|
||||
bones.write[36].handle_offset = Vector2(0.587, 0.52);
|
||||
bones.write[36].group = "RightHand";
|
||||
|
||||
bones.write[37].bone_name = "RightIndexIntermediate";
|
||||
bones.write[37].handle_offset = Vector2(0.597, 0.36);
|
||||
bones.write[37].group = "RightHand";
|
||||
|
||||
bones.write[38].bone_name = "RightIndexDistal";
|
||||
bones.write[38].handle_offset = Vector2(0.597, 0.255);
|
||||
bones.write[38].group = "RightHand";
|
||||
|
||||
bones.write[39].bone_name = "RightMiddleProximal";
|
||||
bones.write[39].handle_offset = Vector2(0.5, 0.51);
|
||||
bones.write[39].group = "RightHand";
|
||||
|
||||
bones.write[40].bone_name = "RightMiddleIntermediate";
|
||||
bones.write[40].handle_offset = Vector2(0.5, 0.345);
|
||||
bones.write[40].group = "RightHand";
|
||||
|
||||
bones.write[41].bone_name = "RightMiddleDistal";
|
||||
bones.write[41].handle_offset = Vector2(0.5, 0.22);
|
||||
bones.write[41].group = "RightHand";
|
||||
|
||||
bones.write[42].bone_name = "RightRingProximal";
|
||||
bones.write[42].handle_offset = Vector2(0.414, 0.52);
|
||||
bones.write[42].group = "RightHand";
|
||||
|
||||
bones.write[43].bone_name = "RightRingIntermediate";
|
||||
bones.write[43].handle_offset = Vector2(0.41, 0.36);
|
||||
bones.write[43].group = "RightHand";
|
||||
|
||||
bones.write[44].bone_name = "RightRingDistal";
|
||||
bones.write[44].handle_offset = Vector2(0.409, 0.25);
|
||||
bones.write[44].group = "RightHand";
|
||||
|
||||
bones.write[45].bone_name = "RightLittleProximal";
|
||||
bones.write[45].handle_offset = Vector2(0.337, 0.543);
|
||||
bones.write[45].group = "RightHand";
|
||||
|
||||
bones.write[46].bone_name = "RightLittleIntermediate";
|
||||
bones.write[46].handle_offset = Vector2(0.328, 0.415);
|
||||
bones.write[46].group = "RightHand";
|
||||
|
||||
bones.write[47].bone_name = "RightLittleDistal";
|
||||
bones.write[47].handle_offset = Vector2(0.328, 0.32);
|
||||
bones.write[47].group = "RightHand";
|
||||
|
||||
bones.write[48].bone_name = "LeftUpperLeg";
|
||||
bones.write[48].handle_offset = Vector2(0.549, 0.49);
|
||||
bones.write[48].group = "Body";
|
||||
|
||||
bones.write[49].bone_name = "LeftLowerLeg";
|
||||
bones.write[49].handle_offset = Vector2(0.548, 0.683);
|
||||
bones.write[49].group = "Body";
|
||||
|
||||
bones.write[50].bone_name = "LeftFoot";
|
||||
bones.write[50].handle_offset = Vector2(0.545, 0.9);
|
||||
bones.write[50].group = "Body";
|
||||
|
||||
bones.write[51].bone_name = "LeftToes";
|
||||
bones.write[51].handle_offset = Vector2(0.545, 0.95);
|
||||
bones.write[51].group = "Body";
|
||||
|
||||
bones.write[52].bone_name = "RightUpperLeg";
|
||||
bones.write[52].handle_offset = Vector2(0.451, 0.49);
|
||||
bones.write[52].group = "Body";
|
||||
|
||||
bones.write[53].bone_name = "RightLowerLeg";
|
||||
bones.write[53].handle_offset = Vector2(0.452, 0.683);
|
||||
bones.write[53].group = "Body";
|
||||
|
||||
bones.write[54].bone_name = "RightFoot";
|
||||
bones.write[54].handle_offset = Vector2(0.455, 0.9);
|
||||
bones.write[54].group = "Body";
|
||||
|
||||
bones.write[55].bone_name = "RightToes";
|
||||
bones.write[55].handle_offset = Vector2(0.455, 0.95);
|
||||
bones.write[55].group = "Body";
|
||||
}
|
||||
|
||||
SkeletonProfileHumanoid::~SkeletonProfileHumanoid() {
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
|
@ -0,0 +1,100 @@
|
|||
/*************************************************************************/
|
||||
/* skeleton_profile.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
|
||||
/* Copyright (c) 2014-2022 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_PROFILE_H
|
||||
#define SKELETON_PROFILE_H
|
||||
|
||||
#include "texture.h"
|
||||
|
||||
class SkeletonProfile : public Resource {
|
||||
GDCLASS(SkeletonProfile, Resource);
|
||||
|
||||
protected:
|
||||
// Note: SkeletonProfileHumanoid which extends SkeletonProfile exists to unify standard bone names.
|
||||
// That is what is_read_only is for, so don't make it public.
|
||||
bool is_read_only = false;
|
||||
|
||||
struct SkeletonProfileGroup {
|
||||
StringName group_name;
|
||||
Ref<Texture2D> texture;
|
||||
};
|
||||
|
||||
struct SkeletonProfileBone {
|
||||
StringName bone_name;
|
||||
Vector2 handle_offset;
|
||||
StringName group;
|
||||
};
|
||||
|
||||
Vector<SkeletonProfileGroup> groups;
|
||||
Vector<SkeletonProfileBone> bones;
|
||||
|
||||
bool _get(const StringName &p_path, Variant &r_ret) const;
|
||||
bool _set(const StringName &p_path, const Variant &p_value);
|
||||
virtual void _validate_property(PropertyInfo &property) const override;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
static void _bind_methods();
|
||||
|
||||
public:
|
||||
int get_group_size();
|
||||
void set_group_size(int p_size);
|
||||
|
||||
StringName get_group_name(int p_group_idx) const;
|
||||
void set_group_name(int p_group_idx, const StringName p_group_name);
|
||||
|
||||
Ref<Texture2D> get_texture(int p_group_idx) const;
|
||||
void set_texture(int p_group_idx, const Ref<Texture2D> &p_texture);
|
||||
|
||||
int get_bone_size();
|
||||
void set_bone_size(int p_size);
|
||||
|
||||
StringName get_bone_name(int p_bone_idx) const;
|
||||
void set_bone_name(int p_bone_idx, const StringName p_bone_name);
|
||||
|
||||
Vector2 get_handle_offset(int p_bone_idx) const;
|
||||
void set_handle_offset(int p_bone_idx, const Vector2 p_handle_offset);
|
||||
|
||||
StringName get_group(int p_bone_idx) const;
|
||||
void set_group(int p_bone_idx, const StringName p_group);
|
||||
|
||||
bool has_bone(StringName p_bone_name);
|
||||
|
||||
SkeletonProfile();
|
||||
~SkeletonProfile();
|
||||
};
|
||||
|
||||
class SkeletonProfileHumanoid : public SkeletonProfile {
|
||||
GDCLASS(SkeletonProfileHumanoid, SkeletonProfile);
|
||||
|
||||
public:
|
||||
SkeletonProfileHumanoid();
|
||||
~SkeletonProfileHumanoid();
|
||||
};
|
||||
|
||||
#endif // SKELETON_PROFILE_H
|