mirror of
https://github.com/Relintai/broken_seals.git
synced 2025-03-08 15:46:59 +01:00
Added arlez80's bone editor from the asset lib as an alternative to the patch.
This commit is contained in:
parent
ec558d1a16
commit
696887b44c
2
game/addons/.gitignore
vendored
2
game/addons/.gitignore
vendored
@ -9,5 +9,7 @@
|
|||||||
!gdpose/**
|
!gdpose/**
|
||||||
!mesh_data_resource_editor
|
!mesh_data_resource_editor
|
||||||
!mesh_data_resource_editor/**
|
!mesh_data_resource_editor/**
|
||||||
|
!bone_editor
|
||||||
|
!bone_editor/**
|
||||||
!addon_versions
|
!addon_versions
|
||||||
|
|
||||||
|
64
game/addons/bone_editor/BoneDock.tscn
Normal file
64
game/addons/bone_editor/BoneDock.tscn
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[sub_resource type="GDScript" id=1]
|
||||||
|
script/source = "tool
|
||||||
|
extends CenterContainer
|
||||||
|
|
||||||
|
var bone_editor
|
||||||
|
|
||||||
|
func _on_Button_pressed( ):
|
||||||
|
if self.bone_editor == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.bone_editor.save_poses( )
|
||||||
|
|
||||||
|
func _on_Button2_pressed():
|
||||||
|
if self.bone_editor == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.bone_editor.init_poses( )
|
||||||
|
|
||||||
|
func _on_Button3_pressed():
|
||||||
|
if self.bone_editor == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.bone_editor.load_poses( )
|
||||||
|
|
||||||
|
"
|
||||||
|
|
||||||
|
[node name="CenterContainer" type="CenterContainer"]
|
||||||
|
margin_right = 40.0
|
||||||
|
margin_bottom = 40.0
|
||||||
|
script = SubResource( 1 )
|
||||||
|
__meta__ = {
|
||||||
|
"_edit_use_anchors_": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[node name="HBoxContainer" type="HBoxContainer" parent="."]
|
||||||
|
margin_left = 44.0
|
||||||
|
margin_top = 10.0
|
||||||
|
margin_right = 324.0
|
||||||
|
margin_bottom = 30.0
|
||||||
|
|
||||||
|
[node name="Button" type="Button" parent="HBoxContainer"]
|
||||||
|
margin_right = 84.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "Insert Keys"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="Button3" type="Button" parent="HBoxContainer"]
|
||||||
|
margin_left = 88.0
|
||||||
|
margin_right = 198.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "Load from Keys"
|
||||||
|
flat = true
|
||||||
|
|
||||||
|
[node name="Button2" type="Button" parent="HBoxContainer"]
|
||||||
|
margin_left = 202.0
|
||||||
|
margin_right = 280.0
|
||||||
|
margin_bottom = 20.0
|
||||||
|
text = "Init Bones"
|
||||||
|
flat = true
|
||||||
|
[connection signal="pressed" from="HBoxContainer/Button" to="." method="_on_Button_pressed"]
|
||||||
|
[connection signal="pressed" from="HBoxContainer/Button3" to="." method="_on_Button3_pressed"]
|
||||||
|
[connection signal="pressed" from="HBoxContainer/Button2" to="." method="_on_Button2_pressed"]
|
168
game/addons/bone_editor/BoneEditor.gd
Normal file
168
game/addons/bone_editor/BoneEditor.gd
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
tool
|
||||||
|
extends Spatial
|
||||||
|
|
||||||
|
export(NodePath) var control_skeleton:NodePath setget set_control_skeleton
|
||||||
|
export(NodePath) var edit_animation_player:NodePath setget set_edit_animation_player
|
||||||
|
export(bool) var enabled:bool = true
|
||||||
|
var skeleton:Skeleton = null
|
||||||
|
var animation_player:AnimationPlayer = null
|
||||||
|
var first_call:bool = true
|
||||||
|
var bone_handle_nodes:Array = []
|
||||||
|
|
||||||
|
func _ready( ):
|
||||||
|
pass
|
||||||
|
|
||||||
|
func set_control_skeleton( path:NodePath ):
|
||||||
|
control_skeleton = path
|
||||||
|
|
||||||
|
if self.first_call:
|
||||||
|
return
|
||||||
|
|
||||||
|
var node:Node = self.get_node( control_skeleton )
|
||||||
|
if node is Skeleton:
|
||||||
|
self.skeleton = node
|
||||||
|
else:
|
||||||
|
self.skeleton = null
|
||||||
|
push_error( str(path) + " does not Skeleton!" )
|
||||||
|
|
||||||
|
self._generate_bone_handles( )
|
||||||
|
|
||||||
|
func set_edit_animation_player( path:NodePath ):
|
||||||
|
edit_animation_player = path
|
||||||
|
|
||||||
|
if self.first_call:
|
||||||
|
return
|
||||||
|
|
||||||
|
var node:Node = self.get_node( edit_animation_player )
|
||||||
|
if node is AnimationPlayer:
|
||||||
|
self.animation_player = node
|
||||||
|
else:
|
||||||
|
self.animation_player = null
|
||||||
|
push_error( str(path) + " does not Animation Player!" )
|
||||||
|
|
||||||
|
func _generate_bone_handles( ):
|
||||||
|
for child in self.get_children( ):
|
||||||
|
self.remove_child( child )
|
||||||
|
|
||||||
|
if self.skeleton == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.bone_handle_nodes = []
|
||||||
|
var bone_handle: = preload( "BoneHandle.tscn" )
|
||||||
|
for bone_id in range( self.skeleton.get_bone_count( ) ):
|
||||||
|
var bone_name:String = self.skeleton.get_bone_name( bone_id )
|
||||||
|
var bone_handle_node:BoneHandle = bone_handle.instance( )
|
||||||
|
|
||||||
|
bone_handle_node.bone_editor = self
|
||||||
|
bone_handle_node.name = bone_name
|
||||||
|
bone_handle_node.skeleton = self.skeleton
|
||||||
|
bone_handle_node.bone_id = bone_id
|
||||||
|
bone_handle_node.bone_name = bone_name
|
||||||
|
|
||||||
|
var parent_bone_id:int = self.skeleton.get_bone_parent( bone_id )
|
||||||
|
if parent_bone_id == -1:
|
||||||
|
self.add_child( bone_handle_node )
|
||||||
|
else:
|
||||||
|
self.bone_handle_nodes[parent_bone_id].add_child( bone_handle_node )
|
||||||
|
|
||||||
|
if Engine.editor_hint == true:
|
||||||
|
var tree:SceneTree = self.get_tree( )
|
||||||
|
if tree != null:
|
||||||
|
if tree.edited_scene_root != null:
|
||||||
|
bone_handle_node.set_owner( tree.edited_scene_root )
|
||||||
|
|
||||||
|
self.bone_handle_nodes.append( bone_handle_node )
|
||||||
|
|
||||||
|
func _process( delta:float ):
|
||||||
|
if self.first_call:
|
||||||
|
self.first_call = false
|
||||||
|
self.set_control_skeleton( self.control_skeleton )
|
||||||
|
self.set_edit_animation_player( self.edit_animation_player )
|
||||||
|
|
||||||
|
for handle_bone in self.bone_handle_nodes:
|
||||||
|
handle_bone.enabled = self.enabled
|
||||||
|
|
||||||
|
func init_poses( ):
|
||||||
|
for handle_bone in self.bone_handle_nodes:
|
||||||
|
handle_bone.init_pose( )
|
||||||
|
|
||||||
|
func load_poses( ):
|
||||||
|
if self.animation_player == null:
|
||||||
|
push_error( "Animation player is null." )
|
||||||
|
return
|
||||||
|
|
||||||
|
var assigned_animation:String = self.animation_player.assigned_animation
|
||||||
|
var animation:Animation = self.animation_player.get_animation( assigned_animation )
|
||||||
|
|
||||||
|
var time:float = self.animation_player.current_animation_position
|
||||||
|
|
||||||
|
for track_idx in animation.get_track_count( ):
|
||||||
|
var target_bone:BoneHandle = null
|
||||||
|
for handle_bone in self.bone_handle_nodes:
|
||||||
|
var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] )
|
||||||
|
if animation.track_get_path( track_idx ) == path:
|
||||||
|
target_bone = handle_bone
|
||||||
|
break
|
||||||
|
if target_bone == null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var bone:Array = animation.transform_track_interpolate( track_idx, time )
|
||||||
|
target_bone.set_pose( Basis( bone[1] ), bone[0] )
|
||||||
|
|
||||||
|
func save_poses( ):
|
||||||
|
if self.animation_player == null:
|
||||||
|
push_error( "Animation player is null." )
|
||||||
|
return
|
||||||
|
|
||||||
|
var assigned_animation:String = self.animation_player.assigned_animation
|
||||||
|
var animation:Animation = self.animation_player.get_animation( assigned_animation )
|
||||||
|
|
||||||
|
if animation == null:
|
||||||
|
push_error( "animation does not selected on Animation player." )
|
||||||
|
return
|
||||||
|
|
||||||
|
# 足りないボーンがあれば追加する
|
||||||
|
self._add_bone_tracks( animation )
|
||||||
|
# ポーズを保存
|
||||||
|
self._save_poses_to_animation( animation )
|
||||||
|
|
||||||
|
func _add_bone_tracks( animation:Animation ):
|
||||||
|
var founded_bone_tracks:Array = []
|
||||||
|
|
||||||
|
for track_idx in animation.get_track_count( ):
|
||||||
|
founded_bone_tracks.append( animation.track_get_path( track_idx ) )
|
||||||
|
|
||||||
|
for handle_bone in self.bone_handle_nodes:
|
||||||
|
var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] )
|
||||||
|
if founded_bone_tracks.find( path ) == -1:
|
||||||
|
var new_track_idx:int = animation.add_track( Animation.TYPE_TRANSFORM )
|
||||||
|
animation.track_set_path( new_track_idx, path )
|
||||||
|
print( "added new track for ", path )
|
||||||
|
|
||||||
|
func _save_poses_to_animation( animation:Animation ):
|
||||||
|
var time:float = self.animation_player.current_animation_position
|
||||||
|
|
||||||
|
for track_idx in animation.get_track_count( ):
|
||||||
|
var target_bone:BoneHandle = null
|
||||||
|
for handle_bone in self.bone_handle_nodes:
|
||||||
|
var path:NodePath = NodePath( "%s:%s" % [ self.get_node( self.animation_player.root_node ).get_path_to( self.skeleton ), handle_bone.name ] )
|
||||||
|
if animation.track_get_path( track_idx ) == path:
|
||||||
|
target_bone = handle_bone
|
||||||
|
break
|
||||||
|
if target_bone == null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# すでに同じ位置にモノが存在するなら削除する
|
||||||
|
for key_idx in animation.track_get_key_count( track_idx ):
|
||||||
|
if animation.track_get_key_time( track_idx, key_idx ) == time:
|
||||||
|
animation.track_remove_key( track_idx, key_idx )
|
||||||
|
break
|
||||||
|
|
||||||
|
animation.transform_track_insert_key(
|
||||||
|
track_idx,
|
||||||
|
time,
|
||||||
|
target_bone.pose.origin,
|
||||||
|
target_bone.pose.basis.get_rotation_quat( ),
|
||||||
|
target_bone.pose.basis.get_scale( )
|
||||||
|
)
|
||||||
|
print( "* added new key for ", target_bone.name )
|
48
game/addons/bone_editor/BoneHandle.gd
Normal file
48
game/addons/bone_editor/BoneHandle.gd
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
tool
|
||||||
|
extends Spatial
|
||||||
|
|
||||||
|
class_name BoneHandle
|
||||||
|
|
||||||
|
var bone_editor
|
||||||
|
var skeleton:Skeleton = null
|
||||||
|
var bone_id:int = -1
|
||||||
|
var bone_name:String = ""
|
||||||
|
var original_rest:Transform
|
||||||
|
var original_parent_rest:Transform
|
||||||
|
var original_global_rest_origin:Vector3
|
||||||
|
var enabled:bool = true
|
||||||
|
|
||||||
|
var pose:Transform
|
||||||
|
|
||||||
|
func _ready( ):
|
||||||
|
if self.skeleton == null or self.bone_id == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.original_rest = self.skeleton.get_bone_rest( self.bone_id )
|
||||||
|
var parent_bone_id:int = self.skeleton.get_bone_parent( self.bone_id )
|
||||||
|
if parent_bone_id != -1:
|
||||||
|
self.original_parent_rest = self.skeleton.get_bone_global_pose( parent_bone_id )
|
||||||
|
|
||||||
|
self.transform.basis = Basis( )
|
||||||
|
self.transform.origin = self.original_parent_rest.basis.xform( self.original_rest.origin )
|
||||||
|
self.original_global_rest_origin = self.transform.origin
|
||||||
|
|
||||||
|
func init_pose( ):
|
||||||
|
self.transform.basis = Basis( )
|
||||||
|
self.transform.origin = self.original_parent_rest.basis.xform( self.original_rest.origin )
|
||||||
|
|
||||||
|
func set_pose( basis:Basis, origin:Vector3 ):
|
||||||
|
self.transform.basis = basis
|
||||||
|
self.transform.origin = self.original_global_rest_origin + self.original_parent_rest.basis.xform( origin )
|
||||||
|
# printt( self.bone_name, basis, origin )
|
||||||
|
|
||||||
|
func _process( delta:float ):
|
||||||
|
if self.skeleton == null or self.bone_id == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.enabled:
|
||||||
|
var t:Transform = Transform( )
|
||||||
|
t.basis = self.transform.basis
|
||||||
|
t.origin = self.original_parent_rest.basis.xform_inv( self.transform.origin - self.original_global_rest_origin )
|
||||||
|
self.skeleton.set_bone_pose( self.bone_id, t )
|
||||||
|
self.pose = t
|
6
game/addons/bone_editor/BoneHandle.tscn
Normal file
6
game/addons/bone_editor/BoneHandle.tscn
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=2]
|
||||||
|
|
||||||
|
[ext_resource path="res://addons/bone_editor/BoneHandle.gd" type="Script" id=1]
|
||||||
|
|
||||||
|
[node name="BoneHandle" type="Spatial"]
|
||||||
|
script = ExtResource( 1 )
|
19
game/addons/bone_editor/LICENSE.txt
Normal file
19
game/addons/bone_editor/LICENSE.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
Copyright (c) 2020 Yui Kinomoto
|
||||||
|
|
||||||
|
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.
|
BIN
game/addons/bone_editor/icon.png
Normal file
BIN
game/addons/bone_editor/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 900 B |
34
game/addons/bone_editor/icon.png.import
Normal file
34
game/addons/bone_editor/icon.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="StreamTexture"
|
||||||
|
path="res://.import/icon.png-98dd89b353351f2740f1a21c6c925c32.stex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/bone_editor/icon.png"
|
||||||
|
dest_files=[ "res://.import/icon.png-98dd89b353351f2740f1a21c6c925c32.stex" ]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_mode=0
|
||||||
|
compress/bptc_ldr=0
|
||||||
|
compress/normal_map=0
|
||||||
|
flags/repeat=1
|
||||||
|
flags/filter=false
|
||||||
|
flags/mipmaps=false
|
||||||
|
flags/anisotropic=false
|
||||||
|
flags/srgb=2
|
||||||
|
process/fix_alpha_border=false
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/HDR_as_SRGB=false
|
||||||
|
process/invert_color=false
|
||||||
|
stream=false
|
||||||
|
size_limit=0
|
||||||
|
detect_3d=false
|
||||||
|
svg/scale=1.0
|
7
game/addons/bone_editor/plugin.cfg
Normal file
7
game/addons/bone_editor/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="bone-editor"
|
||||||
|
description="A bone editor on the editor for Godot Engine 3.2 later"
|
||||||
|
author="arlez80"
|
||||||
|
version="0.0.1"
|
||||||
|
script="plugin.gd"
|
41
game/addons/bone_editor/plugin.gd
Normal file
41
game/addons/bone_editor/plugin.gd
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
const BoneDock = preload( "BoneDock.tscn" )
|
||||||
|
|
||||||
|
var bone_dock_instance
|
||||||
|
var bone_editor
|
||||||
|
|
||||||
|
func _enter_tree( ):
|
||||||
|
self.bone_dock_instance = BoneDock.instance( )
|
||||||
|
self.add_control_to_container( CONTAINER_SPATIAL_EDITOR_MENU, self.bone_dock_instance )
|
||||||
|
self.add_custom_type( "BoneEditor", "Spatial", preload("BoneEditor.gd"), preload("icon.png") )
|
||||||
|
|
||||||
|
func _exit_tree( ):
|
||||||
|
self.remove_custom_type( "BoneEditor" )
|
||||||
|
self.remove_control_from_container( CONTAINER_SPATIAL_EDITOR_MENU, self.bone_dock_instance )
|
||||||
|
self.bone_dock_instance.queue_free( )
|
||||||
|
|
||||||
|
func handles( obj ):
|
||||||
|
if obj is preload("BoneEditor.gd"):
|
||||||
|
self.bone_editor = obj
|
||||||
|
if self.bone_dock_instance != null:
|
||||||
|
self.bone_dock_instance.bone_editor = obj
|
||||||
|
self.bone_dock_instance.visible = true
|
||||||
|
return true
|
||||||
|
elif obj is preload("BoneHandle.gd"):
|
||||||
|
self.bone_editor = obj.bone_editor
|
||||||
|
if self.bone_dock_instance != null:
|
||||||
|
self.bone_dock_instance.bone_editor = obj.bone_editor
|
||||||
|
self.bone_dock_instance.visible = true
|
||||||
|
return true
|
||||||
|
|
||||||
|
self.bone_editor = null
|
||||||
|
if self.bone_dock_instance != null:
|
||||||
|
self.bone_dock_instance.bone_editor = null
|
||||||
|
self.bone_dock_instance.visible = false
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
func get_plugin_name( ):
|
||||||
|
return "Bone Editor"
|
@ -14,6 +14,11 @@ _global_script_classes=[ {
|
|||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
"path": "res://scripts/auras/aura_script.gd"
|
"path": "res://scripts/auras/aura_script.gd"
|
||||||
}, {
|
}, {
|
||||||
|
"base": "Spatial",
|
||||||
|
"class": "BoneHandle",
|
||||||
|
"language": "GDScript",
|
||||||
|
"path": "res://addons/bone_editor/BoneHandle.gd"
|
||||||
|
}, {
|
||||||
"base": "Reference",
|
"base": "Reference",
|
||||||
"class": "BrushPrefabs",
|
"class": "BrushPrefabs",
|
||||||
"language": "GDScript",
|
"language": "GDScript",
|
||||||
@ -221,6 +226,7 @@ _global_script_classes=[ {
|
|||||||
} ]
|
} ]
|
||||||
_global_script_class_icons={
|
_global_script_class_icons={
|
||||||
"AuraGD": "",
|
"AuraGD": "",
|
||||||
|
"BoneHandle": "",
|
||||||
"BrushPrefabs": "",
|
"BrushPrefabs": "",
|
||||||
"CharacterSkeketonAttachPoint": "",
|
"CharacterSkeketonAttachPoint": "",
|
||||||
"DisplayPlayerGD": "",
|
"DisplayPlayerGD": "",
|
||||||
@ -305,7 +311,7 @@ window/size/ui_scale_touch=1.0
|
|||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
enabled=PoolStringArray( "res://addons/Godoxel/plugin.cfg", "res://addons/mesh_data_resource_editor/plugin.cfg" )
|
enabled=PoolStringArray( "res://addons/Godoxel/plugin.cfg", "res://addons/bone_editor/plugin.cfg", "res://addons/mesh_data_resource_editor/plugin.cfg" )
|
||||||
|
|
||||||
[ess]
|
[ess]
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user