mirror of
https://github.com/Relintai/broken_seals.git
synced 2024-12-18 01:06:47 +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/**
|
||||
!mesh_data_resource_editor
|
||||
!mesh_data_resource_editor/**
|
||||
!bone_editor
|
||||
!bone_editor/**
|
||||
!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",
|
||||
"path": "res://scripts/auras/aura_script.gd"
|
||||
}, {
|
||||
"base": "Spatial",
|
||||
"class": "BoneHandle",
|
||||
"language": "GDScript",
|
||||
"path": "res://addons/bone_editor/BoneHandle.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "BrushPrefabs",
|
||||
"language": "GDScript",
|
||||
@ -221,6 +226,7 @@ _global_script_classes=[ {
|
||||
} ]
|
||||
_global_script_class_icons={
|
||||
"AuraGD": "",
|
||||
"BoneHandle": "",
|
||||
"BrushPrefabs": "",
|
||||
"CharacterSkeketonAttachPoint": "",
|
||||
"DisplayPlayerGD": "",
|
||||
@ -305,7 +311,7 @@ window/size/ui_scale_touch=1.0
|
||||
|
||||
[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]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user