Work done during stream 16 and 17

This commit is contained in:
Bastiaan Olij 2020-10-16 23:34:53 +11:00
parent 319b32a43d
commit 795a90154a
9 changed files with 311 additions and 0 deletions

6
.gitattributes vendored Normal file
View File

@ -0,0 +1,6 @@
*.gd eol=lf
*.tscn eol=lf
*.cfg eol=lf
*.godot eol=lf
*.tres eol=lf
*.import eol=lf

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.import/
*.dblite
*.TMP
logs
Thumbs.db

View File

@ -1,2 +1,12 @@
# gdpose # gdpose
Plugin to make skeletons poseable in the editor Plugin to make skeletons poseable in the editor
Note: this is still a work in progress
For more info see my streams on Youtube:
- [Stream #16](https://youtu.be/LtJCLWorenc)
- [Stream #17](https://youtu.be/zFVmMPe9Skc)
# License
This project is provided under an MIT license.
See LICENSE for further details.

View File

@ -0,0 +1,32 @@
tool
extends MenuButton
var skeleton : Skeleton = null
func edit(new_skeleton : Skeleton):
skeleton = new_skeleton
# update our menu
var popup = get_popup()
if popup:
popup.clear()
if skeleton:
for idx in range(0, skeleton.get_bone_count()):
var parent = skeleton.get_bone_parent(idx)
if parent != -1:
var name = skeleton.get_bone_name(idx)
popup.add_item(name, idx)
func select_bone(id):
print("select bone " + str(id))
var gizmo : BoneSpatialGizmo = skeleton.gizmo
if gizmo:
gizmo.set_selected_bone(id)
skeleton.update_gizmo()
func _ready():
var popup = get_popup()
if popup:
popup.connect("id_pressed", self, "select_bone")

View File

@ -0,0 +1,11 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/gdpose/SkeletonPopup.gd" type="Script" id=1]
[node name="SkeletonPopup" type="MenuButton"]
text = "GDPose"
items = [ "Test1", null, 0, false, false, 0, 0, null, "", false, "Test2", null, 0, false, false, 1, 0, null, "", false ]
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}

179
addons/gdpose/bonegizmo.gd Normal file
View File

@ -0,0 +1,179 @@
tool
extends EditorSpatialGizmo
class_name BoneSpatialGizmo
var offset = 0.1
var handle_dist = 0.1 # Distance of gizmo to bone origin
var selected_bone = -1 # Bone we are animating
var is_posing = false
var start_pose = Transform()
var start_point = Vector2()
var handle_idx = Array() # Handles we've added
const handle_rot_x = -2
const handle_rot_y = -3
const handle_rot_z = -4
func set_selected_bone(idx):
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return
if idx >= 0 and idx < skeleton.get_bone_count():
selected_bone = idx
else:
selected_bone = -1
func get_handle_name(index):
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return "No skeleton"
var idx = handle_idx[index]
if idx == handle_rot_x:
return "Rotate X"
elif idx == handle_rot_y:
return "Rotate Y"
elif idx == handle_rot_z:
return "Rotate Z"
else:
return "huh???"
func get_handle_value(index):
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return "No skeleton"
var idx = handle_idx[index]
if selected_bone >= 0:
return skeleton.get_bone_pose(selected_bone)
else:
return "No selected bone"
func set_handle(index, camera, point):
var idx = handle_idx[index]
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return "No skeleton"
if !is_posing:
start_point = point
start_pose = skeleton.get_bone_pose(selected_bone)
is_posing = true
print("start posing " + str(start_pose))
return
var moved = point - start_point
var distance = moved.x + moved.y
# calculate our new transform (in local space)
var new_pose : Transform = start_pose
if idx == handle_rot_x:
# rotate around X
new_pose = new_pose.rotated(start_pose.basis.x.normalized(), distance * 0.01)
elif idx == handle_rot_y:
# rotate around Y
new_pose = new_pose.rotated(start_pose.basis.y.normalized(), distance * 0.01)
elif idx == handle_rot_z:
# rotate around Z
new_pose = new_pose.rotated(start_pose.basis.z.normalized(), distance * 0.01)
skeleton.set_bone_pose(selected_bone, new_pose)
skeleton.update_gizmo()
func commit_handle(index, restore, cancel = false):
# var idx = handle_idx[index]
print("Commit")
is_posing = false
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return
if selected_bone == -1:
return
if (cancel):
skeleton.set_bone_pose(selected_bone, restore)
func redraw():
clear()
var skeleton : Skeleton = get_spatial_node()
if !skeleton:
return
var lines_material = get_plugin().get_material("skeleton", self)
var selected_material = get_plugin().get_material("selected", self)
var handles_material = get_plugin().get_material("handles", self)
var handles = PoolVector3Array()
handle_idx.clear()
# loop through our bones
for idx in range(0, skeleton.get_bone_count()):
var parent = skeleton.get_bone_parent(idx)
if parent != -1:
var lines = PoolVector3Array()
var parent_transform = skeleton.get_bone_global_pose(parent)
var bone_transform = skeleton.get_bone_global_pose(idx)
var parent_pos = parent_transform.origin
var bone_pos = bone_transform.origin
var delta = bone_pos - parent_pos
var length = delta.length()
var p1 = parent_pos + (delta * offset) + parent_transform.basis.x * length * offset
var p2 = parent_pos + (delta * offset) + parent_transform.basis.z * length * offset
var p3 = parent_pos + (delta * offset) - parent_transform.basis.x * length * offset
var p4 = parent_pos + (delta * offset) - parent_transform.basis.z * length * offset
lines.push_back(parent_pos)
lines.push_back(p1)
lines.push_back(p1)
lines.push_back(bone_pos)
lines.push_back(parent_pos)
lines.push_back(p2)
lines.push_back(p2)
lines.push_back(bone_pos)
lines.push_back(parent_pos)
lines.push_back(p3)
lines.push_back(p3)
lines.push_back(bone_pos)
lines.push_back(parent_pos)
lines.push_back(p4)
lines.push_back(p4)
lines.push_back(bone_pos)
lines.push_back(p1)
lines.push_back(p2)
lines.push_back(p2)
lines.push_back(p3)
lines.push_back(p3)
lines.push_back(p4)
lines.push_back(p4)
lines.push_back(p1)
if parent == selected_bone:
add_lines(lines, selected_material, false)
else:
add_lines(lines, lines_material, false)
if idx == selected_bone:
handles.push_back(bone_pos + bone_transform.basis.x * handle_dist)
handle_idx.push_back(handle_rot_x)
handles.push_back(bone_pos + bone_transform.basis.y * handle_dist)
handle_idx.push_back(handle_rot_y)
handles.push_back(bone_pos + bone_transform.basis.z * handle_dist)
handle_idx.push_back(handle_rot_z)
if handles.size() > 0:
add_handles(handles, handles_material)

View File

@ -0,0 +1,22 @@
tool
extends EditorSpatialGizmoPlugin
const BoneGizmo = preload("res://addons/gdpose/bonegizmo.gd")
func get_name():
return "BoneGizmo"
func get_priority():
return 100
func create_gizmo(spatial):
if spatial is Skeleton:
return BoneGizmo.new()
else:
return null
func _init():
create_material("skeleton", Color(0.6, 0.6, 0.0))
create_material("selected", Color(1.0, 1.0, 0.0))
create_handle_material("handles")

7
addons/gdpose/plugin.cfg Normal file
View File

@ -0,0 +1,7 @@
[plugin]
name="gdpose"
description="Pose editor"
author="Bastiaan Olij"
version="1"
script="plugin.gd"

39
addons/gdpose/plugin.gd Normal file
View File

@ -0,0 +1,39 @@
tool
extends EditorPlugin
const BoneGizmoPlugin = preload("res://addons/gdpose/bonegizmoplugin.gd")
const SkeletonPopup = preload("res://addons/gdpose/SkeletonPopup.tscn")
var skeleton_popup_instance
var bone_gizmo = BoneGizmoPlugin.new()
func get_plugin_name():
return "GD Pose Plugin"
func _enter_tree():
# Initialization of the plugin goes here.
add_spatial_gizmo_plugin(bone_gizmo)
# add our menu
skeleton_popup_instance = SkeletonPopup.instance()
add_control_to_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, skeleton_popup_instance)
skeleton_popup_instance.visible = false
func _exit_tree():
remove_spatial_gizmo_plugin(bone_gizmo)
if skeleton_popup_instance:
remove_control_from_container(EditorPlugin.CONTAINER_SPATIAL_EDITOR_MENU, skeleton_popup_instance)
skeleton_popup_instance.queue_free()
skeleton_popup_instance = null
func make_visible(visible):
if skeleton_popup_instance:
skeleton_popup_instance.visible = visible
func handles(object):
return object is Skeleton
func edit(object):
var skeleton : Skeleton = object
if skeleton_popup_instance:
skeleton_popup_instance.edit(skeleton)