예제 #1
0
def gen_properties_offset_keyframe(curve_list, animated, i):
    """
    Generates the dictionary corresponding to properties/offsetKeyFrame.json

    Args:
        curve_list (list)                : Stores bezier curve in Lottie format
        animated   (lxml.etree._Element) : Synfig format animation
        i          (int)                 : Iterator for animation

    Returns:
        (TypeError) : If a constant interval is encountered
        (None)      : In all other cases
    """
    lottie = curve_list[-1]

    waypoint, next_waypoint = animated[i], animated[i + 1]
    cur_get_after, next_get_before = waypoint.attrib[
        "after"], next_waypoint.attrib["before"]
    cur_get_before, next_get_after = waypoint.attrib[
        "before"], next_waypoint.attrib["after"]

    # "angle" interpolations never call this function, can be removed by confirming
    if animated.attrib["type"] == "angle":
        if cur_get_after == "auto":
            cur_get_after = "linear"
        if cur_get_before == "auto":
            cur_get_before = "linear"
        if next_get_before == "auto":
            next_get_before = "linear"
        if next_get_after == "auto":
            next_get_after = "linear"

    # Synfig only supports constant interpolations for points
    # "points" never call this function, can be removed by confirming
    if animated.attrib["type"] == "points":
        cur_get_after = "constant"
        cur_get_before = "constant"
        next_get_after = "constant"
        next_get_before = "constant"

    # Calculate positions of waypoints
    cur_pos = parse_position(animated, i)
    next_pos = parse_position(animated, i + 1)

    lottie["i"] = {}  # Time bezier curve, not used in synfig
    lottie["o"] = {}  # Time bezier curve, not used in synfig
    lottie["i"]["x"] = 0.5
    lottie["i"]["y"] = 0.5
    lottie["o"]["x"] = 0.5
    lottie["o"]["y"] = 0.5
    if cur_get_after == "halt":  # For ease out
        ease_out(lottie)
    if next_get_before == "halt":  # For ease in
        ease_in(lottie)
    lottie["t"] = get_frame(waypoint)

    is_transform_axis = False
    if "transform_axis" in animated.keys():
        is_transform_axis = True
    lottie["s"] = change_axis(cur_pos[0], cur_pos[1], is_transform_axis)
    lottie["e"] = change_axis(next_pos[0], next_pos[1], is_transform_axis)
    lottie["to"] = []
    lottie["ti"] = []

    # Calculating the unchanged tangent
    try:
        out_val, in_val = calc_tangent(animated, lottie, i)
    except Exception as excep:
        # This means constant interval
        return excep

    # This module is only needed for origin animation
    lottie["to"] = out_val.get_list()
    lottie["ti"] = in_val.get_list()

    # TCB/!TCB and list is not empty
    if cur_get_before == "auto" and cur_get_after != "auto" and i > 0:
        curve_list[-2]["ti"] = copy.deepcopy(lottie["to"])
        curve_list[-2]["ti"] = [
            -item / settings.TANGENT_FACTOR for item in curve_list[-2]["ti"]
        ]
        curve_list[-2]["ti"][1] = -curve_list[-2]["ti"][1]
        if cur_get_after == "halt":
            curve_list[-2]["i"]["x"] = settings.IN_TANGENT_X
            curve_list[-2]["i"]["y"] = settings.IN_TANGENT_Y

    # Lottie tangent length is larger than synfig
    lottie["ti"] = [item / settings.TANGENT_FACTOR for item in lottie["ti"]]
    lottie["to"] = [item / settings.TANGENT_FACTOR for item in lottie["to"]]

    # Lottie and synfig use different tangents SEE DOCUMENTATION
    lottie["ti"] = [-item for item in lottie["ti"]]

    # IMPORTANT to and ti have to be relative
    # The y-axis is different in lottie
    lottie["ti"][1] = -lottie["ti"][1]
    lottie["to"][1] = -lottie["to"][1]

    # These tangents will be used in actual calculation of points according to
    # Synfig
    lottie["synfig_to"] = [tangent for tangent in lottie["to"]]
    lottie["synfig_ti"] = [-tangent for tangent in lottie["ti"]]
    if cur_get_after == "halt":
        lottie["synfig_to"] = [0 for val in lottie["synfig_to"]]
    if next_get_before == "halt":
        lottie["synfig_ti"] = [0 for val in lottie["synfig_ti"]]
예제 #2
0
def gen_value_Keyframe(curve_list, animated, i):
    """
    Generates the dictionary corresponding to properties/valueKeyframe.json in lottie
    documentation

    Args:
        curve_list (list)                : Bezier curve in Lottie format
        animated   (lxml.etree._Element) : Synfig format animation
        i          (int)                 : Iterator for animation

    Returns:
        (TypeError) : If hold interval is encountered
        (None)      : Otherwise
    """
    lottie = curve_list[-1]
    waypoint, next_waypoint = animated[i], animated[i + 1]
    cur_get_after, next_get_before = waypoint.attrib[
        "after"], next_waypoint.attrib["before"]
    cur_get_before, next_get_after = waypoint.attrib[
        "before"], next_waypoint.attrib["after"]
    # Calculate positions of waypoints
    if animated.attrib["type"] in {"angle", "star_angle_new", "region_angle"}:
        #if animated.attrib["type"] in {"angle"}:
        if cur_get_after == "auto":
            cur_get_after = "linear"
        if cur_get_before == "auto":
            cur_get_before = "linear"
        if next_get_before == "auto":
            next_get_before = "linear"
        if next_get_after == "auto":
            next_get_after = "linear"

    # Synfig only supports constant interpolations for points
    if animated.attrib["type"] == "points":
        cur_get_after = "constant"
        cur_get_before = "constant"
        next_get_after = "constant"
        next_get_before = "constant"

    # After effects only supports linear,ease-in,ease-out and constant interpolations for color
    ##### No support for TCB and clamped interpolations in color is there yet #####
    if animated.attrib["type"] == {"color", "linear_gradient"}:
        if cur_get_after in {"auto", "clamped"}:
            cur_get_after = "linear"
        if cur_get_before in {"auto", "clamped"}:
            cur_get_before = "linear"
        if next_get_before in {"auto", "clamped"}:
            next_get_before = "linear"
        if next_get_after in {"auto", "clamped"}:
            next_get_after = "linear"

    cur_pos = parse_position(animated, i)
    next_pos = parse_position(animated, i + 1)

    lottie["t"] = get_frame(waypoint)
    lottie["s"] = cur_pos.get_val()
    lottie["e"] = next_pos.get_val()

    lottie["i"] = {}
    lottie["o"] = {}

    try:
        out_val, in_val = calc_tangent(animated, lottie, i)
    except Exception as excep:
        # That means halt/constant interval
        return excep

    set_tangents(out_val, in_val, cur_pos, next_pos, lottie, animated)

    if cur_get_after == "halt":  # For ease out
        lottie["o"]["x"][0] = settings.OUT_TANGENT_X
        lottie["o"]["y"][0] = settings.OUT_TANGENT_Y
        lottie["synfig_o"] = [0]
    if next_get_before == "halt":  # For ease in
        lottie["i"]["x"][0] = settings.IN_TANGENT_X
        lottie["i"]["y"][0] = settings.IN_TANGENT_Y
        lottie["synfig_i"] = [0]

    # TCB/!TCB and list is not empty
    if cur_get_before == "auto" and cur_get_after != "auto" and i > 0:

        # need value for previous tangents
        # It may be helpful to store them somewhere
        prev_ov, prev_iv = calc_tangent(animated, curve_list[-2], i - 1)
        prev_iv = out_val
        set_tangents(prev_ov, prev_iv, parse_position(animated, i - 1),
                     cur_pos, curve_list[-2], animated)
        if cur_get_after == "halt":
            curve_list[-2]["i"]["x"][0] = settings.IN_TANGENT_X
            curve_list[-2]["i"]["y"][0] = settings.IN_TANGENT_Y
            lottie["synfig_i"] = [0]
예제 #3
0
def calc_tangent(animated, lottie, i):
    """
    Calculates the tangent, given two waypoints and there interpolation methods

    Args:
        animated (lxml.etree._Element) : Synfig format animation
        lottie   (dict)                : Lottie format animation stored here
        i        (int)                 : Iterator for animation

    Returns:
        (Misc.Vector) : If waypoint's value is parsed to misc.Vector by misc.parse_position()
        (Misc.Color)  : If waypoint's value is parsed to misc.Color ...
        (float)       : If waypoint's value is parsed to float ...
        (None)        : If "constant" interval is detected
    """
    waypoint, next_waypoint = animated[i], animated[i + 1]
    cur_get_after, next_get_before = waypoint.attrib[
        "after"], next_waypoint.attrib["before"]
    cur_get_before, next_get_after = waypoint.attrib[
        "before"], next_waypoint.attrib["after"]

    if animated.attrib["type"] in {"angle", "star_angle_new", "region_angle"}:
        #if animated.attrib["type"] in {"angle"}:
        if cur_get_after == "auto":
            cur_get_after = "linear"
        if cur_get_before == "auto":
            cur_get_before = "linear"
        if next_get_before == "auto":
            next_get_before = "linear"
        if next_get_after == "auto":
            next_get_after = "linear"

    # Synfig only supports constant interpolations for points
    if animated.attrib["type"] == "points":
        cur_get_after = "constant"
        cur_get_before = "constant"
        next_get_after = "constant"
        next_get_before = "constant"

    # After effects only supports linear,ease-in,ease-out and constant interpolations for color
    ##### No support for TCB and clamped interpolations in color is there yet #####
    if animated.attrib["type"] == "color":
        if cur_get_after in {"auto", "clamped"}:
            cur_get_after = "linear"
        if cur_get_before in {"auto", "clamped"}:
            cur_get_before = "linear"
        if next_get_before in {"auto", "clamped"}:
            next_get_before = "linear"
        if next_get_after in {"auto", "clamped"}:
            next_get_after = "linear"

    # Calculate positions of waypoints
    cur_pos = parse_position(animated, i)
    prev_pos = copy.deepcopy(cur_pos)
    next_pos = parse_position(animated, i + 1)
    after_next_pos = copy.deepcopy(next_pos)

    if i + 2 <= len(animated) - 1:
        after_next_pos = parse_position(animated, i + 2)
    if i - 1 >= 0:
        prev_pos = parse_position(animated, i - 1)

    tens, bias, cont = 0, 0, 0  # default values
    tens1, bias1, cont1 = 0, 0, 0
    if "tension" in waypoint.keys():
        tens = float(waypoint.attrib["tension"])
    if "continuity" in waypoint.keys():
        cont = float(waypoint.attrib["continuity"])
    if "bias" in waypoint.keys():
        bias = float(waypoint.attrib["bias"])
    if "tension" in next_waypoint.keys():
        tens1 = float(next_waypoint.attrib["tension"])
    if "continuity" in next_waypoint.keys():
        cont1 = float(next_waypoint.attrib["continuity"])
    if "bias" in next_waypoint.keys():
        bias1 = float(next_waypoint.attrib["bias"])

    ### Special case for color interpolations ###
    if animated.attrib["type"] == "color":
        if cur_get_after == "linear" and next_get_before == "linear":
            return handle_color()

    # iter           next
    # ANY/TCB ------ ANY/ANY
    if cur_get_after == "auto":
        if i >= 1:
            out_val = ((1 - tens) * (1 + bias) * (1 + cont) *\
                       (cur_pos - prev_pos))/2 +\
                       ((1 - tens) * (1 - bias) * (1 - cont) *\
                       (next_pos - cur_pos))/2
        else:
            out_val = next_pos - cur_pos  # t1 = p2 - p1

    # iter           next
    # ANY/LINEAR --- ANY/ANY
    # ANY/EASE   --- ANY/ANY
    if cur_get_after in {"linear", "halt"}:
        out_val = next_pos - cur_pos

    # iter          next
    # ANY/ANY ----- LINEAR/ANY
    # ANY/ANY ----- EASE/ANY
    if next_get_before in {"linear", "halt"}:
        in_val = next_pos - cur_pos

    # iter          next
    # ANY/CLAMPED - ANY/ANY
    if cur_get_after == "clamped":
        if i >= 1:
            ease = "out"
            out_val = clamped_vector(prev_pos, cur_pos, next_pos, animated, i,
                                     lottie, ease)
        else:
            out_val = next_pos - cur_pos  # t1 = p2 - p1

    # iter          next             after_next
    # ANY/ANY ----- CLAMPED/ANY ---- ANY/ANY
    if next_get_before == "clamped":
        if i + 2 <= len(animated) - 1:
            ease = "in"
            in_val = clamped_vector(cur_pos, next_pos, after_next_pos,
                                    animated, i + 1, lottie, ease)
        else:
            in_val = next_pos - cur_pos  # t2 = p2 - p1

    # iter              next
    # ANY/CONSTANT ---- ANY/ANY
    # ANY/ANY      ---- CONSTANT/ANY
    if cur_get_after == "constant" or next_get_before == "constant":
        lottie["h"] = 1
        if animated.attrib["type"] == "vector":
            del lottie["to"], lottie["ti"]
        del lottie["i"], lottie["o"]
        # "e" is not needed, but is still not deleted as
        # it is of use in the last iteration of animation
        # See properties/multiDimenstionalKeyframed.py for more details
        # del lottie["e"]

        # If the number of points is decresing, then hold interpolation should
        # have reverse effect. The value should instantly decrease and remain
        # same for the rest of the interval
        if animated.attrib["type"] == "points":
            if i > 0 and prev_pos[0] > cur_pos[0]:
                t_now = get_frame(animated[i - 1]) + 1
                lottie["t"] = t_now
        return

    # iter           next           after_next
    # ANY/ANY ------ TCB/ANY ------ ANY/ANY
    if next_get_before == "auto":
        if i + 2 <= len(animated) - 1:
            in_val = ((1 - tens1) * (1 + bias1) * (1 - cont1) *\
                      (next_pos - cur_pos))/2 +\
                      ((1 - tens1) * (1 - bias1) * (1 + cont1) *\
                      (after_next_pos - next_pos))/2
        else:
            in_val = next_pos - cur_pos  # t2 = p2 - p1
    return out_val, in_val