auto_walk/OP_world_copy_paste.py

166 lines
6.1 KiB
Python
Raw Normal View History

2021-04-08 19:25:05 +02:00
import bpy
from . import fn
class AW_OT_world_space_copy(bpy.types.Operator):
bl_idname = "pose.world_space_copy"
2021-04-08 19:25:05 +02:00
bl_label = "World Copy"
bl_description = "Copy world space transforms. Store active bone matrix"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
return context.object and context.mode == 'POSE' and context.active_pose_bone
def execute(self, context):
bpy.types.ViewLayer.world_space_store = context.object.matrix_world @ context.active_pose_bone.matrix
return {"FINISHED"}
class AW_OT_world_space_paste(bpy.types.Operator):
bl_idname = "pose.world_space_paste"
2021-04-08 19:25:05 +02:00
bl_label = "World Paste"
bl_description = "Paste world space transforms. Apply stored matrix to active bone and key LocRotScale"
2021-04-08 19:25:05 +02:00
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
if not hasattr(bpy.context.view_layer, 'world_space_store'):
cls.poll_message_set("Nothing To Paste")
return False
2021-04-08 19:25:05 +02:00
return context.object and context.mode == 'POSE' and context.active_pose_bone
def execute(self, context):
context.active_pose_bone.matrix = context.object.matrix_world.inverted() @ bpy.context.view_layer.world_space_store
## only if autokey is On
# if context.scene.tool_settings.use_keyframe_insert_auto:
# bpy.ops.anim.keyframe_insert_menu(type='LocRotScale') # Available
## always paste location rotation scale
bpy.ops.anim.keyframe_insert(type='LocRotScale')
2021-04-08 19:25:05 +02:00
return {"FINISHED"}
class AW_OT_world_space_paste_next(bpy.types.Operator):
bl_idname = "pose.world_space_paste_next"
2021-04-08 19:25:05 +02:00
bl_label = "World Paste Jump"
bl_description = "Paste world space transforms and keyframe available chanels\
\nThen jump to prev/next key\
\nKey Loc rot scale only"
2021-04-08 19:25:05 +02:00
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
if not hasattr(bpy.context.view_layer, 'world_space_store'):
cls.poll_message_set("Nothing To Paste")
return False
2021-04-08 19:25:05 +02:00
return context.object and context.mode == 'POSE' and context.active_pose_bone
prev: bpy.props.BoolProperty()
def execute(self, context):
# apply matrix
context.active_pose_bone.matrix = context.object.matrix_world.inverted() @ bpy.context.view_layer.world_space_store
# insert keyframe at value
bpy.ops.anim.keyframe_insert(type='LocRotScale') # delete args to use default
2021-04-08 19:25:05 +02:00
# jump to next key
act = fn.get_obj_action(context.object)
if not act:
self.report({'ERROR'}, 'No action on armature')
return {'CANCELLED'}
kx = [k.co.x for fcu in act.fcurves
if fcu.data_path.split('"')[1] == context.active_pose_bone.bone.name
for k in fcu.keyframe_points]
if not kx:
self.report({'ERROR'}, 'No keys on action available (no keyframe added)')
return {'CANCELLED'}
# for fcu in act.fcurves:
# if fcu.data_path.split('"')[1] == context.active_pose_bone.bone.name:
if self.prev:
new_frame = next((k for k in reversed(kx) if k < context.scene.frame_current), None)
else:
new_frame = next((k for k in kx if k > context.scene.frame_current), None)
if not new_frame:
self.report({'WARNING'}, 'No next frame to jump on')
return {'FINISHED'}
context.scene.frame_current = int(new_frame)
2021-04-08 19:25:05 +02:00
return {"FINISHED"}
class AW_OT_world_space_paste_next_frame(bpy.types.Operator):
bl_idname = "pose.world_space_paste_next_frame"
bl_label = "World Paste Jump Frame"
bl_description = "Paste world space transforms and keyframe available chanels\
\nThen jump to prev/next frame\
\nKey Loc rot scale only"
bl_options = {"REGISTER", "UNDO"}
@classmethod
def poll(cls, context):
if not hasattr(bpy.context.view_layer, 'world_space_store'):
cls.poll_message_set("Nothing To Paste")
return False
return context.object and context.mode == 'POSE' and context.active_pose_bone
prev: bpy.props.BoolProperty()
def execute(self, context):
# apply matrix
context.active_pose_bone.matrix = context.object.matrix_world.inverted() @ bpy.context.view_layer.world_space_store
# context.object.keyframe_insert(data_path, index=-1, frame=bpy.context.scene.frame_current, group="", options={'INSERTKEY_AVAILABLE'})
## bpy.ops.anim.keyframe_insert(type='DEFAULT')
## possible type :
# 'Location', 'Rotation', 'Scaling', 'BUILTIN_KSI_LocRot', 'LocRotScale', 'LocRotScaleCProp',
# 'BUILTIN_KSI_LocScale', 'BUILTIN_KSI_RotScale',
# 'BUILTIN_KSI_DeltaLocation', 'BUILTIN_KSI_DeltaRotation', 'BUILTIN_KSI_DeltaScale',
# 'BUILTIN_KSI_VisualLoc', 'BUILTIN_KSI_VisualRot', 'BUILTIN_KSI_VisualScaling',
# 'BUILTIN_KSI_VisualLocRot', 'BUILTIN_KSI_VisualLocRotScale', 'BUILTIN_KSI_VisualLocScale', 'BUILTIN_KSI_VisualRotScale'
## insert keyframe at value
## Insert Keyframes for specified Keying Set, with menu of available Keying Sets if undefined
# bpy.ops.anim.keyframe_insert_menu(type='Available', always_prompt=False)
## Insert keyframes on the current frame for all properties in the specified Keying Set
bpy.ops.anim.keyframe_insert(type='LocRotScale')
# jump to next frame
act = fn.get_obj_action(context.object)
if not act:
self.report({'ERROR'}, 'No action on armature')
return {'CANCELLED'}
offset = -1 if self.prev else 1
new_frame = context.scene.frame_current + offset
context.scene.frame_current = new_frame
return {"FINISHED"}
2021-04-08 19:25:05 +02:00
classes=(
AW_OT_world_space_copy,
AW_OT_world_space_paste,
AW_OT_world_space_paste_next,
AW_OT_world_space_paste_next_frame,
2021-04-08 19:25:05 +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)