#!/usr/bin/env python # # bbb-fusion-animate-cursor.py # # Script meant to be executed from Fusion console to automatically import # cursors.xml movements as XOffset/Yoffset on a Shape Transform node. # # Copyright (c) 2023 Sylvain Munaut # SPDX-License-Identifier: MIT # import bbb def gen_keyframes(cursor, framerate=24, res_x=1280, res_y=720): mr = max(res_x, res_y) kx = {} ky = {} hidden = None lf = None for t,x,y in cursor: # Frame number f = round(t * framerate) # Hide event ? if (x < 0) or (y < 0): if lf is not None: kx[f-1] = { 1: lx } ky[f-1] = { 1: ly } kx[f] = { 1: -1 } ky[f] = { 1: -1 } hidden = True continue # Coordinate mapping x = ((x - 0.5) * res_x / mr) y = -((y - 0.5) * res_y / mr) # If there was no movement for 2 seconds, hide if (lf is not None) and ((f - lf) >= (2 * framerate)) and not hidden: kx[lf + framerate - 1] = { 1: lx } ky[lf + framerate - 1] = { 1: ly } kx[lf + framerate ] = { 1: -1 } ky[lf + framerate ] = { 1: -1 } kx[f - framerate ] = { 1: -1 } ky[f - framerate ] = { 1: -1 } kx[f - framerate + 1] = { 1: lx } ky[f - framerate + 1] = { 1: ly } # If we were hidden, add keyframe just before if hidden: kx[f-1] = { 1: -1 } ky[f-1] = { 1: -1 } hidden = False # Add keyframes kx[f] = { 1: x } ky[f] = { 1: y } # Save last coord lx = x ly = y lf = f return kx, ky def animate_cursor(cursor_file, shape_xform, width=None, height=None, framerate=None): # Get data if width is None: width = comp.GetPrefs("Comp.FrameFormat.Width") if height is None: height = comp.GetPrefs("Comp.FrameFormat.Height") if framerate is None: framerate = comp.GetPrefs("Comp.FrameFormat.Rate") # Load cursor events ce = bbb.parse_cursor_xml(cursor_file) # Generate keyframes kx, ky = gen_keyframes(ce, res_x=width, res_y=height, framerate=framerate) # Get Shape Transform and apply keyframes tool = comp.FindTool(shape_xform) bx = comp.BezierSpline() bx.SetKeyFrames(kx) by = comp.BezierSpline() by.SetKeyFrames(ky) tool.XOffset = bx tool.YOffset = by # Edit the following as needed and run using comp.RunScript in the Fusion console print("Running ...") animate_cursor("cursor.xml", "CursorPos") print("Done")