auto_walk/panels.py

290 lines
12 KiB
Python
Raw Permalink Normal View History

2021-04-05 01:35:12 +02:00
import bpy
2021-04-06 18:30:25 +02:00
from . import fn
2021-04-05 01:35:12 +02:00
class AW_PT_walk_cycle_anim_panel(bpy.types.Panel):
2021-04-05 01:35:12 +02:00
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Walk"
bl_label = "Auto Walk"
2021-04-05 01:35:12 +02:00
def draw(self, context):
layout = self.layout
prefs = fn.get_addon_prefs()
ob = context.object
2022-03-29 18:46:33 +02:00
settings = context.scene.anim_cycle_settings
tweak = settings.tweak
2022-03-29 18:46:33 +02:00
# need to know root orientation forward)
## know direction to evaluate feet moves
## Define Constraint axis (depend on root orientation)
# layout.prop(settings, "forward_axis") # plain prop
col = layout.column()
row = col.row()
row.label(text='Forward Axis')
row.prop(settings, "forward_axis", text='')
row.operator('autowalk.open_addon_prefs', icon='PREFERENCES', text='')
col.operator("autowalk.autoset_axis", text='Auto-Set Axis') # maybe check for fcruve cycle at the end of autoset axis ? (like a check)
col.operator("autowalk.create_cycles_modifiers", text='Add Cycles Modifiers', icon='GRAPH')
pb = None
constrained = False
if ob and ob.type == 'ARMATURE':
pb = ob.pose.bones.get(prefs.tgt_bone)
if pb:
follow = pb.constraints.get('Follow Path')
if follow and follow.target:
constrained = True
if not settings.path_to_follow and not constrained:
layout.operator('autowalk.create_curve_path', text='Create Curve at Root Position', icon='CURVE_BEZCURVE')
if (w_co := context.scene.collection.children.get('walk_markers')) and w_co.objects:
row=layout.row(align=True)
row.label(text=f"1st Point Frame {w_co.objects[0].name.split('_')[-1]}")
row.operator('autowalk.remove_a_b_step', text='', icon='X') # Remove
layout.operator('autowalk.create_a_b_step', text='Set 2nd Point', icon='CURVE_PATH')
else:
layout.operator('autowalk.create_a_b_step', text='Set 1st Point', icon='CURVE_PATH')
else:
layout.operator('autowalk.edit_curve', text='Edit Curve', icon='OUTLINER_DATA_CURVE') # FORCE_CURVE
2022-03-31 17:07:04 +02:00
elif ob and ob.type == 'CURVE':
if context.mode in ('OBJECT', 'EDIT_CURVE') \
and settings.path_to_follow \
and ob == settings.path_to_follow:
layout.operator('autowalk.object_from_curve', text='Back To Object', icon='LOOP_BACK')
box = layout.box()
expand_icon = 'TRIA_DOWN' if tweak else 'TRIA_RIGHT'
box.prop(settings, 'tweak', text='Curve Options', icon=expand_icon)
if tweak:
#-# path and ground objects
box.prop(settings, "tgt_bone", text='Bone')
box.prop_search(settings, "path_to_follow", context.scene, "objects")
box.prop_search(settings, "gnd", context.scene, "objects")
2021-04-06 18:30:25 +02:00
row = box.row()
if ob and ob.type == 'ARMATURE':
row.operator('autowalk.snap_curve_to_ground', text='Snap Curve To Ground', icon='SNAP_ON')
elif ob and ob.type == 'CURVE':
row.operator('autowalk.snap_selected_curve', text='Snap Selected Curve To Ground', icon='SNAP_ON')
else:
row.label(text='Select curve or armature to snap', icon='INFO')
row.active = bool(settings.gnd)
# Determine if already has a constraint (a bit too much condition in a panel...)
if ob:
if ob.type == 'ARMATURE':
pb = ob.pose.bones.get(prefs.tgt_bone)
if pb:
follow = pb.constraints.get('Follow Path')
if follow and follow.target:
row = box.row()
row.label(text=f'{pb.name} -> {follow.target.name}', icon='CON_FOLLOWPATH')
row.operator('autowalk.remove_follow_path', text='', icon='X')
constrained = True
## Put this in a setting popup or submenu
# if context.mode == 'POSE':
if not constrained:
box.operator('autowalk.create_follow_path', text='Add follow path constraint', icon='CON_FOLLOWPATH')
2021-04-05 01:35:12 +02:00
box = layout.box()
col=box.column()
col.label(text='Motion:')
row = col.row(align=True)
row.prop(settings, "start_frame", text='Start')
row.prop(settings, "end_frame", text='End')
col.operator('autowalk.animate_path', text='Move On Curve', icon='ANIM') # Animate Forward Motion
2021-04-05 01:35:12 +02:00
row=col.row()
row.operator('autowalk.adjust_animation_length', text='Adjust Speed', icon='MOD_TIME') # Adjust Forward Speed
2021-04-05 01:35:12 +02:00
2021-04-06 18:30:25 +02:00
## Bake cycle (on selected)
box = layout.box()
col=box.column()
col.label(text='Action:')
row=col.row()
2022-03-29 18:46:33 +02:00
row.prop(settings, "linear", text='Linear')
row.prop(settings, "expand_on_selected_bones")
2022-03-31 17:07:04 +02:00
txt = 'Bake keys' if settings.linear else 'Bake keys and step path'
col.operator('autowalk.bake_cycle_and_step', text=txt, icon='SHAPEKEY_DATA')
2021-04-05 01:35:12 +02:00
# Custom Axis Pinning
subox = col.box()
subox.prop(settings, "custom_pin", text='Custom Pinning')
if settings.custom_pin:
row=subox.row(align=True)
row.label(text='Location')
row.prop(settings, 'pin_loc_x', text='X', toggle=True)
row.prop(settings, 'pin_loc_y', text='Y', toggle=True)
row.prop(settings, 'pin_loc_z', text='Z', toggle=True)
row=subox.row(align=True)
row.label(text='Rotation')
row.prop(settings, 'pin_rot_x', text='X', toggle=True)
row.prop(settings, 'pin_rot_y', text='Y', toggle=True)
row.prop(settings, 'pin_rot_z', text='Z', toggle=True)
2021-04-05 01:35:12 +02:00
# Pin feet
col.operator('autowalk.pin_feets', text='Pin feets', icon='PINNED')
## show a dropdown allowing to go back to unpinned, unbaked version of the animation
if ob and ob.type == 'ARMATURE':
anim = ob.animation_data
if anim and anim.action and not anim.use_tweak_mode:
# skipped if in NLA tweak mode because anim.is_property_readonly('action') = True
if 'baked' in anim.action.name or 'pinned' in anim.action.name:
col=box.column()
col.operator('autowalk.step_back_actions', text='Use Previous Actions', icon= 'ACTION')
2021-04-05 01:35:12 +02:00
class AW_MT_wrap_animation_help(bpy.types.Menu):
# bl_idname = "OBJECT_MT_custom_menu"
bl_label = "Wrap Animation Infos"
def draw(self, context):
layout = self.layout
col = layout.column()
# col.label(text='Wrap animation:', icon='INFO')
col.label(text='Apply offset from ref bone to root bone')
col.label(text='on all selected pose bones')
col.separator()
col.label(text='Example:')
col.label(text='Root is the bone to return to. Often root/walk/world bone')
col.label(text='In most cases, Ref bone will be the bottom spine bone')
col.label(text='Applying with spine selected will align spine with root on X-Y axis')
# col.separator()
# col.label(text='Note: If resulted animation is broken', icon='ERROR')
# col.label(text='try applying with only one selected bone at a time')
class AW_OT_bone_eye_dropper(bpy.types.Operator):
bl_idname = "auto_walk.bone_eye_dropper"
bl_label = "Bone Eye Dropper"
bl_description = "Fill the field with active pose bone"
bl_options = {'INTERNAL'}
field : bpy.props.StringProperty()
prop : bpy.props.StringProperty()
def execute(self, context):
prop = self.prop
field = eval(self.field)
setattr(field, prop, context.active_pose_bone.name)
return {'FINISHED'}
class AW_PT_wrap_animation_panel(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Walk"
bl_label = "Wrap Anim"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
col = layout.column()
if not context.object or context.object.type != 'ARMATURE':
col.label(text='Active object must be of Armature type')
return
row = col.row()
row.label(text='Offset Reference to Root')
row.operator("wm.call_menu", text="", icon='QUESTION').name = "AW_MT_wrap_animation_help"
settings = context.scene.anim_cycle_settings
for prop_name in ("wrap_root_bone", "wrap_ref_bone"):
row = col.row()
row.prop_search(settings, prop_name, context.object.pose, "bones")
eyedrop = row.operator('auto_walk.bone_eye_dropper', text='', icon='EYEDROPPER')
eyedrop.field = repr(settings)
eyedrop.prop = prop_name
col.operator('autowalk.wrap_animation', text='Wrap Animation') # , icon=''
class AW_PT_anim_tools_panel(bpy.types.Panel):
2021-04-06 18:30:25 +02:00
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "Walk"
bl_label = "Pin Tools"
2021-04-06 18:30:25 +02:00
def draw(self, context):
layout = self.layout
## FIXME: need to fix vertices get
# layout.operator('autowalk.contact_to_ground', text='Ground selected feet', icon='SNAP_OFF')
2021-04-08 19:25:05 +02:00
row = layout.row()
row.operator('pose.world_space_copy', text='Copy Pose', icon='COPYDOWN')
# row.operator('autowalk.world_space_paste', text='Paste', icon='PASTEDOWN')
# row = layout.row(align=False)
## multi buttons
# row.label(text='Paste and jump:')
# row = layout.row(align=True)
# row.operator('autowalk.world_space_paste_next', text='Prev key', icon='PREV_KEYFRAME').prev = True # Paste Prev key
# row.operator('autowalk.world_space_paste_next', text='Next key', icon='NEXT_KEYFRAME').prev = False # Paste Next key
# row = layout.row(align=True)
# row.operator('autowalk.world_space_paste_next_frame', text='Prev frame', icon='FRAME_PREV').prev = True # Paste Prev frame
# row.operator('autowalk.world_space_paste_next_frame', text='Next frame', icon='FRAME_NEXT').prev = False # Paste Next frame
row = layout.row(align=True)
row.operator('pose.world_space_paste_next_frame', text='', icon='FRAME_PREV').prev = True
row.operator('pose.world_space_paste_next', text='', icon='PREV_KEYFRAME').prev = True
row.operator('pose.world_space_paste', text='', icon='PASTEDOWN')
row.operator('pose.world_space_paste_next', text='', icon='NEXT_KEYFRAME').prev = False
row.operator('pose.world_space_paste_next_frame', text='', icon='FRAME_NEXT').prev = False
row.scale_x = 2
2021-04-08 19:25:05 +02:00
class AW_PT_nla_tools_panel(bpy.types.Panel):
bl_space_type = "NLA_EDITOR"
bl_region_type = "UI"
bl_category = "Strip"
bl_label = "Walk Tools"
def draw(self, context):
layout = self.layout
# layout.label(text='Retime Tools')
settings = context.scene.anim_cycle_settings
row = layout.row(align=True)
row.operator('autowalk.nla_key_speed', text='Set/Update Time Keys', icon='TIME')
row.operator('autowalk.nla_remove_key_speed', text='', icon='X')
2021-04-05 01:35:12 +02:00
classes=(
AW_PT_walk_cycle_anim_panel,
AW_PT_anim_tools_panel,
AW_PT_nla_tools_panel,
AW_MT_wrap_animation_help,
AW_OT_bone_eye_dropper,
AW_PT_wrap_animation_panel,
)
classes_override_category =(
AW_PT_walk_cycle_anim_panel,
AW_PT_anim_tools_panel,
2021-04-05 01:35:12 +02:00
)
## Addons Preferences Update Panel
def update_panel(self, context):
for cls in classes_override_category: # classes
try:
bpy.utils.unregister_class(cls)
except:
pass
cls.bl_category = self.category # fn.get_addon_prefs().category
bpy.utils.register_class(cls)
2021-04-05 01:35:12 +02:00
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)