Beispiel #1
0
 def save_quats():
     quats = [0, 0, 0, 0]
     for index in range(4):
         fc = Get.fcurve(action, keypath, index=index)
         if fc:
             quats[index] = len(fc.keyframe_points)
     return quats
Beispiel #2
0
def fcurve(action, path, index=-1, group=""):
    """Create a new fcurve in an action if it doesn't exist"""

    if group is None:
        group = ""

    fc = Get.fcurve(action, path, index)
    if fc is None:
        fc = action.fcurves.new(path, index=index, action_group=group)

    return fc
Beispiel #3
0
 def restore_quats(skip):
     nonlocal quats
     for index in range(4):
         if index == skip:
             continue
         fc = Get.fcurve(action, keypath, index=index)
         if fc and len(fc.keyframe_points) > quats[index]:
             for key in fc.keyframe_points:
                 if key.co.x == tweak_frame:
                     fc.keyframe_points.remove(key)
                     break
             else:
                 # Shouldn't happen but backup in case fail to find key
                 key_args = dict(index=index, frame=frame, group=group)
                 if sub is None:
                     src.keyframe_delete(path, **key_args)
                 else:
                     sub.keyframe_delete(path, **key_args)
Beispiel #4
0
def manual(context, src, path, **kargs):
    "Insert a keyframe manually. Sub is for sub targets, like constraints"
    # kargs:
    # sub=None, index=-1, frame=None, value=None,
    # group=None, insert_key=None, action=None, context=None

    insert_key = kargs.get('insert_key', None)
    sub = kargs.get('sub', None)
    index = kargs.get('index', -1)
    frame = kargs.get('frame', None)
    value = kargs.get('value', None)
    group = kargs.get('group', None)
    action = kargs.get('action', None)
    results = kargs.get('results', list())
    options = kargs.get('options', set())
    delete = kargs.get('delete', False)

    keyframe_type = kargs.get('type',
                              context.scene.tool_settings.keyframe_type)

    if not keyframe.poll_insert(context, insert_key, src=src):
        return results

    # if frame is None:
    #     frame = context.scene.frame_current
    # if group is None:
    #     group = keyframe.group_name(src)
    # src.keyframe_insert(path, index=index, frame=frame, group=group)
    # return

    if group is None:
        group = keyframe.group_name(src)

    obj = src.id_data
    anim = obj.animation_data_create()
    if action is None:
        key_in_action = True
        action = anim.action
        if action is None:
            action = anim.action = bpy.data.actions.new("Action")
    else:
        # When using a specified action, don't insert
        # keyframes later to determine the property's value
        key_in_action = False

    if frame is None:
        frame = context.scene.frame_current_final

    strip = Get.active_strip(anim) if anim.use_tweak_mode else None

    if strip:
        if not (strip.frame_start <= frame <= strip.frame_end):
            # frame outside of the strip's bounds
            key_in_action = False

        tweak_frame = Get.frame_to_strip(context, anim, frame=frame)
    else:
        tweak_frame = frame

    if Is.posebone(src) and not path.startswith('pose.bones'):
        keypath = utils.string('pose.bones[\"', src.name, '\"]',
                               '' if path.startswith('[') else '.', path)
    elif not Is.object(src) and hasattr(src, 'path_from_id'):
        keypath = src.path_from_id(path)
    else:
        keypath = path

    # Find the value(s) to insert keyframes for
    if hasattr(sub, path):
        base = getattr(sub, path)
    elif hasattr(src, path):
        base = getattr(src, path)
    else:
        base = eval(f'{obj!r}.{keypath}')

    if value is None:
        prop = base
    else:
        if Is.iterable(base) and not Is.iterable(value):
            prop = [value for i in base]
        elif not Is.iterable(base) and Is.iterable(value):
            prop = value[(index, 0)[index == -1]]
        else:
            prop = value

    if (not Is.iterable(prop)):
        if index != -1:
            index = -1
        if (not Is.iterable(prop)):
            props = [(index, prop)]
        else:
            props = [(index, prop[index])]
    elif (index == -1):
        props = list(enumerate(prop))
    else:
        props = [(index, prop[index])]

    def save_quats():
        quats = [0, 0, 0, 0]
        for index in range(4):
            fc = Get.fcurve(action, keypath, index=index)
            if fc:
                quats[index] = len(fc.keyframe_points)
        return quats

    def restore_quats(skip):
        nonlocal quats
        for index in range(4):
            if index == skip:
                continue
            fc = Get.fcurve(action, keypath, index=index)
            if fc and len(fc.keyframe_points) > quats[index]:
                for key in fc.keyframe_points:
                    if key.co.x == tweak_frame:
                        fc.keyframe_points.remove(key)
                        break
                else:
                    # Shouldn't happen but backup in case fail to find key
                    key_args = dict(index=index, frame=frame, group=group)
                    if sub is None:
                        src.keyframe_delete(path, **key_args)
                    else:
                        sub.keyframe_delete(path, **key_args)

    if path.endswith('rotation_quaternion') and (
        (strip and strip.blend_type == 'COMBINE') or
        (not strip and anim.action_blend_type == 'COMBINE')):
        # Combine forces keyframe insertion on all 4 channels, so reset them
        quats = save_quats()
    else:
        quats = None

    # Create curve(s) (if needed) and keyframe(s)
    for (i, v) in props:
        fc = Get.fcurve(action, keypath, i)
        new_fc = not bool(fc)
        if new_fc:
            fc = New.fcurve(action, keypath, index=i, group=group)

        if fc.lock:
            # Internal ops don't allow keyframing locked channels, so :p
            results.append((fc, None))
            continue

        if delete:
            results.append((fc, src.keyframe_delete(path, frame=frame)))
            continue

        count = len(fc.keyframe_points)

        if (value is None) and key_in_action:
            key_args = dict(index=i, frame=frame, group=group, options=options)
            if sub is None:
                src.keyframe_insert(path, **key_args)
            else:
                sub.keyframe_insert(path, **key_args)
            v = fc.evaluate(tweak_frame)

        key = fc.keyframe_points.insert(tweak_frame, v, options={'FAST'})
        # options=set({'REPLACE', 'NEEDED', 'FAST'})
        # src.keyframe_insert(path, index=i, frame=frame, group=group)

        if quats:
            restore_quats(skip=i)
            quats[i] = len(fc.keyframe_points)
            # Update key count for current index, to not remove it later

        # Update keyframe to use default preferences values

        edit = utils.prefs().edit

        key.handle_left_type = key.handle_right_type = \
            edit.keyframe_new_handle_type
        if new_fc:
            # When inserting keyframes, only change their interpolation type if the fcurve is new
            key.interpolation = edit.keyframe_new_interpolation_type

        if len(fc.keyframe_points) > count:
            # New keyframe was added
            key.type = keyframe_type

        results.append((fc, key))

    if kargs.get('index', -1) == -1:
        return results
    else:
        return results[0]