# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####


bl_info = {
    "name": "Export Fusion Composition",
    "author": "Michael Vorberg, Christian Brinkmann",
    "version": (0, 6, 0),
    "blender": (2, 80, 0),
    "location": "File > Export > Fusion Comp (.comp)",
    "description": "Export Cameras and PointClouds of motion tracking into a Fusion Composition(.comp)",
    "warning": "",
    "category": "Import-Export",
}

import bpy
from bpy_extras.io_utils import ExportHelper, axis_conversion
import math
import mathutils
import os


def write_cameras(context, filepath, frame_start, frame_end, only_selected=False):

    data_attrs = (
        'lens',
        'shift_x',
        'shift_y',
        'dof_distance',
        'clip_start',
        'clip_end',
        'draw_size',
        )

    scene = context.scene  
    
    bl_display_colorspace = scene.display_settings.display_device
    #print (bl_display_colorspace)
    
    fu_display_colorspace = ""
    
    try: 
        if bl_display_colorspace == "sRGB":
            fu_display_colorspace = "sRGB"
        elif bl_display_colorspace == "Rec709":
            fu_display_colorspace = "Rec709Display"
        elif bl_display_colorspace == "XYZ":
            fu_display_colorspace = "DCI"
        elif bl_display_colorspace == "None":
            fu_display_colorspace = "No Change"
        elif bl_display_colorspace == "Filmic":
            fu_display_colorspace = ""
        elif bl_display_colorspace == "sRGB / BT.709":
            fu_display_colorspace = "sRGB"
    except:
        fu_display_colorspace = ""

    rot_x_neg90 = mathutils.Matrix.Rotation(-math.pi/2.0, 4, 'X')

    obj_attrs = (
        'hide_render',
        )

    with open(filepath, "w") as fw:
        cameras = []

        for obj in scene.objects:
            if only_selected and not obj.select_get():
                continue
            if obj.type != 'CAMERA':
                continue
            cameras.append((obj, obj.data))
        if len(cameras) == 0:
            raise RuntimeError("no camera selected but \"only selected\" activated")
            
        # write some settings for the composition
        frame_range = range(frame_start, frame_end + 1)
        fw.write("Composition {\n"
                 "   CurrentTime = 0,\n")
        fw.write("   RenderRange = { %d, %d, },\n"%(frame_start, frame_end))
        fw.write("   GlobalRange = { %d, %d, },\n"%(frame_start, frame_end))
        fw.write("""Prefs = {
        Comp = {
                Views = {
                Right = {
                    Viewer = {
                        EnableLUTs = true,
                        LUTPlugin = "GamutViewLUT",
                        LUTSelected = "Gamut View LUT",
                    },
                    ViewLUT = {
                        {
                            Tools = ordered() {
                                GamutViewLUT1 = ViewOperator {
                                    CtrlWZoom = false,
                                    NameSet = true,
                                    Inputs = {""")
        fw.write("                  OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace)
        fw.write("""                },
                                },
                            },
                            ID = "GamutViewLUT",
                        },
                        SelectedPlugin = "GamutViewLUT",
                        SelectedName = "Gamut View LUT",
                    },
                },
                Left = {
                    Viewer = {
                        EnableLUTs = true,
                        LUTPlugin = "GamutViewLUT",
                        LUTSelected = "Gamut View LUT",
                    },
                    ViewLUT = {
                        {
                            Tools = ordered() {
                                GamutViewLUT = ViewOperator {
                                    CtrlWZoom = false,
                                    NameSet = true,
                                    Inputs = {""")
        fw.write("                  OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace)
        fw.write("""                },
                                },
                            },
                            ID = "GamutViewLUT",
                        },
                        SelectedPlugin = "GamutViewLUT",
                        SelectedName = "Gamut View LUT",
                    },
                },
                View1 = {
                },
            },
            FrameFormat = {
                Name = "Multimedia", """)
        fw.write("Width = %d,\n"%(scene.render.resolution_x))
        fw.write("Height = %d,\n"%(scene.render.resolution_y))
        fw.write("Rate = %d,\n"%(scene.render.fps))
        fw.write("""PerFeet = 1,
                GuideRatio = 1.77777777777778,
            },
            },
            Views = {
            Right = {
                SideB = {
                    PrevCtrlInactiveColor = 65280,
                    PickW = 1,
                    PickH = 1,
                    PrevCtrlActiveColor = 255,
                    Viewer = {
                        EnableLUTs = false,
                        LUTPlugin = "FusionViewLUT",
                        FitMarginY = 0,
                        FitMarginX = 0,
                        FitMarginType = 0,
                        FarZ = -1000,
                        NearZ = 0,
                    },
                },
                Viewer = {
                    EnableLUTs = true,
                    LUTPlugin = "GamutViewLUT",
                    LUTSelected = "Gamut View LUT",
                },
                ViewLUT = {
                    {
                        Tools = ordered() {
                            GamutViewLUT1 = ViewOperator {
                                NameSet = true,
                                Inputs = {""")
        fw.write("                  OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace)
        fw.write("""                        },
                                CtrlWZoom = false,
                            },
                        },
                        ID = "GamutViewLUT",
                    },
                    Recent = {
                        SelectedPlugin = "GamutViewLUT",
                        FusionViewLUT = {
                            Tools = ordered() {
                                FusionViewLUT = ViewLUTOp {
                                    NameSet = true,
                                    Inputs = {
                                    },
                                },
                            },
                        },
                        SelectedName = "Gamut View LUT",
                    },
                    SelectedName = "Gamut View LUT",
                    SelectedPlugin = "GamutViewLUT",
                },
            },
            Left = {
                SideB = {
                    PrevCtrlInactiveColor = 65280,
                    PickW = 1,
                    PickH = 1,
                    PrevCtrlActiveColor = 255,
                    Viewer = {
                        EnableLUTs = false,
                        LUTPlugin = "FusionViewLUT",
                        FitMarginY = 0,
                        FitMarginX = 0,
                        FitMarginType = 0,
                        FarZ = -1000,
                        NearZ = 0,
                    },
                },
                Viewer = {
                    EnableLUTs = true,
                    LUTPlugin = "GamutViewLUT",
                    LUTSelected = "Gamut View LUT",
                },
                ViewLUT = {
                    {
                        Tools = ordered() {
                            GamutViewLUT = ViewOperator {
                                NameSet = true,
                                Inputs = {""")
        fw.write("                  OutputSpace = Input { Value = FuID { \"%s\", }, },"%fu_display_colorspace)
        fw.write("""                        },
                                CtrlWZoom = false,
                            },
                        },
                        ID = "GamutViewLUT",
                    },
                    SelectedPlugin = "GamutViewLUT",
                    SelectedName = "Gamut View LUT",
                },
            },
            View1 = {
                PrevCtrlInactiveColor = 0,
                PickW = 1,
                PickH = 1,
                PrevCtrlActiveColor = 0,
                SideB = {
                    PrevCtrlInactiveColor = 65280,
                    PickW = 1,
                    PickH = 1,
                    PrevCtrlActiveColor = 255,
                    Viewer = {
                        EnableLUTs = false,
                        LUTPlugin = "FusionViewLUT",
                        FitMarginY = 0,
                        FitMarginX = 0,
                        FitMarginType = 0,
                        FarZ = -1000,
                        NearZ = 0,
                    },
                },
            },
        },
        },
        """)
        # starting with the actual nodes
        fw.write("Tools = {\n")
        # look if we have a clip in the scene and create a loader node for it
        try:
            if bpy.data.movieclips[0]:
                fw.write("""Loader1 = Loader {
                    Clips = {
                        Clip {
                            ID = "Clip1",\n""")
                clip_filepath = os.path.normpath(bpy.data.movieclips[0].filepath)
                clip_filepath_four_slashes = clip_filepath.replace("\\", "\\\\")
                fw.write("Filename = \" %s \",\n"%(clip_filepath_four_slashes))
                fw.write("StartFrame = %d,\n"%(frame_start))
                fw.write("Length = %d,\n"%(frame_end))
                fw.write("LengthSetManually = true,\n")
                fw.write("TrimIn = %d,\n"%(frame_start-1))
                fw.write("TrimOut = %d,\n"%(frame_end-1))
                fw.write("""ExtendFirst = 0,
                            ExtendLast = 0,
                            Loop = 1,
                            AspectMode = 0,
                            Depth = 0,
                            TimeCode = 0,""")
                fw.write("GlobalStart = %d,\n"%(frame_start))
                fw.write("GlobalEnd = %d,\n"%(frame_end))
                fw.write("""},
                    },
                    ViewInfo = OperatorInfo { Pos = { 300, 0, }, },
                    CtrlWZoom = false,
                },
                Gamut1 = GamutConvert {
                    Inputs = {
                        SourceSpace = Input { Value = FuID { "sRGB", }, },
                            Input = Input {
                                            SourceOp = "Loader1",
                                            Source = "Output",
                            },
                    },
                    ViewInfo = OperatorInfo { Pos = { 300, 100, }, },
                },""")
        except:
            print("No clip found for Loader")
            
        # create Camera3D nodes
        try:
            for obj, obj_data in cameras:
                fw.write("       Camera3D_%s = Camera3D {\n" %obj_data.name.replace(".", "_").replace(".", "_"))
                fw.write("           CtrlWZoom = false,\n"
                         "           Inputs = {\n"
                         "               [\"PerspNearClip\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_PerspNearClip\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                  Source = \"Value\",\n"
                         "               },\n"
                         "               [\"PerspFarClip\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_PerspFarClip\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                  Source = \"Value\",\n"
                         "               },\n"
                         "               [\"FLength\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_LensFlength\",\n"  %obj_data.name.replace(".", "_"))
                fw.write("                  Source = \"Value\",\n"
                         "               },\n"
                         "               [\"PlaneOfFocus\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_PlaneOfFocus\",\n"  %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n"
                         "               },\n"
                         "               [\"Transform3DOp.Translate.X\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_XOffset\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n"
                         "               },\n"
                         "               [\"Transform3DOp.Translate.Y\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_YOffset\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n"
                         "               },\n"
                         "               [\"Transform3DOp.Translate.Z\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_ZOffset\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n")
                fw.write("               },\n"
                         "               [\"Transform3DOp.Rotate.X\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_XRotation\",\n"%obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n")
                fw.write("               },\n"
                         "               [\"Transform3DOp.Rotate.Y\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_YRotation\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n")
                fw.write("               },\n"
                         "               [\"Transform3DOp.Rotate.Z\"] = Input {\n"
                         "                   SourceOp = \"Camera3D_%s_ZRotation\",\n" %obj_data.name.replace(".", "_"))
                fw.write("                   Source = \"Value\",\n")
                fw.write("               },\n")
                fw.write("              [\"Stereo.Mode\"] = Input { Value = FuID { \"Mono\", }, },\n"
                         "               FilmBack = Input { Value = 1, },\n"
                         "               FilmGate = Input { Value = FuID { \"User\", }, },\n")
                fw.write("              LensShiftX = Input { Value = %r, },\n" %(-obj_data.shift_x))
                fw.write("              LensShiftY = Input { Value = %r, },\n" %(-obj_data.shift_y*(scene.render.resolution_x/scene.render.resolution_y)))
                ap_w = float(obj_data.sensor_width) / 25.4
                fw.write("              ApertureW = Input { Value = %s, },\n" %str(ap_w))
                ap_h = ap_w/(scene.render.resolution_x/scene.render.resolution_y)
                fw.write("              ApertureH = Input { Value = %s, },\n" %str(ap_h))
                if obj_data.sensor_fit == "HORIZONTAL":
                    fw.write("              AovType = Input { Value = 1, },\n")
                if obj_data.sensor_fit == "VERTICAL":
                    fw.write("              AovType = Input { Value = 0, },\n")
                fw.write('''                [\"SurfacePlaneInputs.ObjectID.ObjectID\"] = Input { Value = 1, },\n
                                    [\"MtlStdInputs.MaterialID\"] = Input { Value = 1, },\n
                                },\n
                                 ViewInfo = OperatorInfo { Pos = { 0, 100, }, },
                            },\n'''
                         )
                fw.write("      Camera3D_%s_XOffset = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write('''            NameSet = true,\n
                            KeyFrames = {\n''')
                # X Translation
                for f in frame_range:
                    scene.frame_set(f)
                    matrix = obj.matrix_world.copy()
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, matrix.to_translation()[0]))
                fw.write("  },\n"
                         "},\n")
                # Y Translation (Fusion Y)
                fw.write("      Camera3D_%s_YOffset = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    matrix = obj.matrix_world.copy()
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, matrix.to_translation()[2]))
                fw.write("  },\n"
                         "},\n")
                # Z Translation (Fusion Z)
                fw.write("      Camera3D_%s_ZOffset = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    matrix = obj.matrix_world.copy()
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, -matrix.to_translation()[1]))
                fw.write("  },\n"
                         "},\n")
                # X Rotation (Fusion X)
                fw.write("      Camera3D_%s_XRotation = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    matrix_org = obj.matrix_world.copy()
                    matrix = rot_x_neg90 * matrix_org
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, (math.degrees(matrix.to_euler()[0]))))
                fw.write("  },\n"
                         "},\n")
                # Y Rotation (Fusion Y)
                fw.write("      Camera3D_%s_YRotation = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    matrix_org = obj.matrix_world.copy()
                    matrix = rot_x_neg90 * matrix_org
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, math.degrees(matrix.to_euler()[1])))
                fw.write("  },\n"
                         "},\n")
                # Z Rotation (Fusion Z)
                fw.write("      Camera3D_%s_ZRotation = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    matrix_org = obj.matrix_world.copy()
                    matrix = rot_x_neg90 * matrix_org
                    fw.write("  [%d] = { %r, Flags = { Linear = true, }, },\n" %(f, math.degrees(matrix.to_euler()[2])))
                fw.write("  },\n"
                         "},\n")
                fw.write("      Camera3D_%s_LensFlength = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.lens))
                fw.write("  },\n"
                         "},\n")
                         
                fw.write("      Camera3D_%s_PlaneOfFocus = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.dof_distance))
                fw.write("  },\n"
                         "},\n")
                fw.write("      Camera3D_%s_PerspNearClip = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write("       NameSet = true,\n"
                         "       KeyFrames = {\n")
                for f in frame_range:
                    scene.frame_set(f)
                    fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.clip_start))
                fw.write("  },\n"
                         "},\n")
                fw.write("      Camera3D_%s_PerspFarClip = BezierSpline {\n" %obj_data.name.replace(".", "_"))
                fw.write('''                NameSet = true,\n
                                KeyFrames = {\n''')
                for f in frame_range:
                    scene.frame_set(f)
                    fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, obj_data.clip_end))
                fw.write('''  },\n
                   },\n''')
                obj.select_set(False)
        except:
            print("No camera found/selected")
        # write pointcloud3D node
        # look if we have a clip in the scene
        try:
            if bpy.data.movieclips[0]:
                fw.write('''
                    PointCloud3D1 = PointCloud3D {\n
                    CtrlWZoom = false,\n
                    ViewInfo = OperatorInfo { Pos = { 150, 0, }, },\n
                    Positions = {\n
                        Version = 0,\n
                    ''')
                curr_clip = bpy.data.movieclips[0]
                zeroPosition = [0, 0, 0]
                sceneCamera = bpy.data.objects['Camera']
                track_list = []
                for track in curr_clip.tracking.tracks:
                    if track.has_bundle is False:
                        continue
                    track_list.append(track)
                for track in track_list:
                    track_name = track.name
                    bpy.ops.object.add(type='EMPTY',location = [0, 0, 0])
                    current_obj = context.active_object
                    bpy.ops.object.constraint_add(type="FOLLOW_TRACK")
                    context.object.constraints["Follow Track"].use_3d_position = True
                    context.object.constraints["Follow Track"].object = "Camera"
                    context.object.constraints["Follow Track"].track = track_name
                    context.object.constraints["Follow Track"].camera = sceneCamera
                    current_obj_data = bpy.data.objects[current_obj.name]
                    current_obj_data.name = track_name
                    print ("created object: ", current_obj_data.name)
                
                i = 0
                for track in track_list:
                    track_name = track.name
                    current_obj = context.active_object
                    current_obj_data = bpy.data.objects[track_name]
                    obj_name_matrix = current_obj_data.matrix_world.copy()
                    fw.write(
                             "[%d] = { %r, %r, %r, \"%s\", \"\", },\n" % (
                                i, obj_name_matrix.to_translation()[0], 
                                obj_name_matrix.to_translation()[2], 
                                -obj_name_matrix.to_translation()[1], 
                                track_name
                            )
                    )
                    i += 1
                    current_obj_data.select_set(True)
                
                # delete all helper tracks
                bpy.ops.object.delete(use_global=False)
                # close pointcloud3D and create Merge3D
                fw.write('''  },\n
                       },\n               
                       Merge3D1 = Merge3D {
                       Inputs = {
                       SceneInput1 = Input {''')
                try:
                    if not obj_data.name:
                        fw.write("SourceOp = \"Camera3D_%s\",\n" % obj_data.name.replace(".", "_").replace(".", "_"))
                    else:
                        fw.write("SourceOp = \"\",\n")
                except:
                    raise RuntimeError("no camera selected")
                fw.write('''Source = \"Output\",
                        },
                        SceneInput2 = Input {
                            SourceOp = \"PointCloud3D1\",
                            Source = \"Output\",
                        },
                    },
                    ViewInfo = OperatorInfo { Pos = { 151, 100, }, },
                },''')
        except:
            print("No clip found")
            
        try:
            if bpy.data.movieclips[0]:    
                #create2d trackers
                print ("trying 2d tracks")
                curr_clip = bpy.data.movieclips[0]
                track_list = []
                for track in curr_clip.tracking.tracks:
                    if track.has_bundle is False:
                        continue
                    track_list.append(track)
                fw.write("""
                        Tracker1 = Tracker {
                            Trackers = {
                                """)    
                                
                for track in track_list:
                    track_name = track.name.replace(".", "_")
                    track_name_orig = track.name
                    fw.write("""{
                                    PatternTime = 1,
                                    PatternX = 0.392840626111704,
                                    PatternY = 0.699857685009488,
                                },""")
                                
                fw.write("""},
                            CtrlWZoom = false,
                            Inputs = {TrackerList = Input { Value = 1, },""")
                i = 0            
                for track in track_list:
                    track_name = track.name.replace(".", "_")
                    track_name_orig = track.name
                    i += 1
                    fw.write("Name%d = Input { Value = \"%s\", }," %(i, track_name))
                    fw.write("PatternCenter%d = Input { Value = { %r, %r, }, },"% (
                            i, bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers[0].co.x,
                            bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers[0].co.y)
                            )
                    fw.write("PatternWidth%d = Input { Value = 0.0154571326929918, },"%i)
                    fw.write("PatternHeight%d = Input { Value = 0.020841239721695, },"%i)
                    fw.write("SearchWidth%d = Input { Value = 0.0574350764852365, },"%i)
                    fw.write("SearchHeight%d = Input { Value = 0.0714421252371915, }," %i)
                    fw.write("TrackedCenter%d = Input {" %i)
                    fw.write("SourceOp = \"Tracker1%sXYPath\"," %track_name)
                    fw.write("""Source = "Value",
                                },
                            """)
                            
                fw.write("""},\n ViewInfo = OperatorInfo { Pos = { 500, 0, }, },
                            },""")
                            
                for track in track_list:
                    track_name = track.name.replace(".", "_")
                    track_name_orig = track.name
                    print ("creating animation for 2d tracker: ", track_name)
                    
                    fw.write("Tracker1%sXYPath = XYPath {" %track_name)
                    fw.write("""ShowKeyPoints = false,
                                DrawMode = "ModifyOnly",
                                CtrlWZoom = false,
                                NameSet = true,
                                Inputs = {
                                    X = Input {""")
                    fw.write("SourceOp = \"XYPath_%sX\"," %track_name)
                    fw.write("""Source = "Value",
                                    },
                                    Y = Input {""")
                    fw.write("SourceOp = \"XYPath_%sY\"," %track_name)
                    fw.write("""Source = "Value",
                                    },
                                },
                            },
                    """)
                    fw.write("XYPath_%sX = BezierSpline {" %track_name)
                    fw.write("""SplineColor = { Red = 255, Green = 0, Blue = 0, },
                        NameSet = true,
                        KeyFrames = {
                    """)
                    for f in frame_range:
                        marker_at_frame = bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers.find_frame(f)
                        if not marker_at_frame:
                            continue
                        fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, marker_at_frame.co.x))
                    fw.write("""  },\n
                    },\n""")
                    fw.write("XYPath_%sY = BezierSpline {" %track_name)
                    fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                        NameSet = true,
                        KeyFrames = {
                    """)
                    for f in frame_range:
                        marker_at_frame = bpy.data.movieclips[0].tracking.tracks[track_name_orig].markers.find_frame(f)
                        if not marker_at_frame:
                            continue
                        fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(f, marker_at_frame.co.y))
                    fw.write("""  },\n
                   },\n""")
            #create lens distortion node       
            fw.write("""LensDistort1 = LensDistort {
            CtrlWZoom = false,
            Inputs = {
                LensDistortionModel = Input { Value = 1, },
                Model = Input { Value = FuID { "PFTrack", }, },\n""")
            fw.write("[\"PFTrack.LowOrderDistortion\"] = Input { Value = %r, },\n" %-bpy.data.movieclips[0].tracking.camera.k1)
            fw.write("[\"PFTrack.HighOrderDistortion\"] = Input { Value = %r, },\n" %-bpy.data.movieclips[0].tracking.camera.k2)
            fw.write("[\"PFTrack.LensCenterX\"] = Input { Value = %r, },\n" % (bpy.data.movieclips[0].tracking.camera.principal[0]/bpy.data.movieclips[0].size[0]))
            fw.write("[\"PFTrack.LensCenterY\"] = Input { Value = %r, },\n" %(bpy.data.movieclips[0].tracking.camera.principal[1]/bpy.data.movieclips[0].size[1]))
            fw.write("""},
                    ViewInfo = OperatorInfo { Pos = { 700, 0, }, },
                    },
                """)
        except:
            print("No clip found")
        
        try:
            if bpy.data.movieclips[0]: 
                curr_clip = bpy.data.movieclips[0]
                plane_track_list = []
            
                for plane_track in curr_clip.tracking.plane_tracks:
                    plane_track_list.append(plane_track)
                 
                if len(plane_track_list)>0:
                    for i,track in enumerate(plane_track_list):
                        track_name = track.name.replace(".", "_")
                        track_name_orig = track.name
                        fw.write("CornerPositioner%d = CornerPositioner {" %i)
                        fw.write('''Inputs = {
                                    TopLeft = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath\"," %i)
                        fw.write('''Source = "Value",
                                },
                                TopRight = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath\"," %i)
                        fw.write('''Source = "Value",
                                },
                                BottomLeft = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath\"," %i)
                        fw.write('''Source = "Value",
                                },
                                BottomRight = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath\"," %i)
                        fw.write('''Source = "Value",
                                },
                            },''')
                        toolPos = 900+i*100
                        fw.write("ViewInfo = OperatorInfo { Pos = { %d, 0, }, }," %toolPos)
                        fw.write('''},''')
                        
                        fw.write("PlaneTrack%dTrack1XYPath = XYPath {" %i)
                        fw.write('''ShowKeyPoints = false,
                                    DrawMode = "InsertAndModify",
                                    NameSet = true,
                                    Inputs = {
                                        X = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath%dX\"," %(i,i))
                        fw.write('''Source = "Value",
                                },
                                Y = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath%dY\"," %(i,i))
                        fw.write('''Source = "Value",
                                            },
                                        },
                                    },''')
                                    
                        fw.write("PlaneTrack%dTrack2XYPath = XYPath {" %i)
                        fw.write('''ShowKeyPoints = false,
                                    DrawMode = "InsertAndModify",
                                    NameSet = true,
                                    Inputs = {
                                        X = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath%dX\"," %(i,i))
                        fw.write('''Source = "Value",
                                },
                                Y = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath%dY\"," %(i,i))
                        fw.write('''Source = "Value",
                                            },
                                        },
                                    },''')
                                    
                        fw.write("PlaneTrack%dTrack3XYPath = XYPath {" %i)
                        fw.write('''ShowKeyPoints = false,
                                    DrawMode = "InsertAndModify",
                                    NameSet = true,
                                    Inputs = {
                                        X = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath%dX\"," %(i,i))
                        fw.write('''Source = "Value",
                                },
                                Y = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath%dY\"," %(i,i))
                        fw.write('''Source = "Value",
                                            },
                                        },
                                    },''')
                                    
                        fw.write("PlaneTrack%dTrack4XYPath = XYPath {" %i)
                        fw.write('''ShowKeyPoints = false,
                                    DrawMode = "InsertAndModify",
                                    NameSet = true,
                                    Inputs = {
                                        X = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath%dX\"," %(i,i))
                        fw.write('''Source = "Value",
                                },
                                Y = Input {''')
                        fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath%dY\"," %(i,i))
                        fw.write('''Source = "Value",
                                            },
                                        },
                                    },''')
                        fw.write("PlaneTrack%dTrack1XYPath%dX = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[3][0]))
                        fw.write("""  },\n
                                },\n""")
                        fw.write("PlaneTrack%dTrack1XYPath%dY = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[3][1]))
                        fw.write("""  },\n
                                },\n""")
                        
                        fw.write("PlaneTrack%dTrack2XYPath%dX = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[2][0]))
                        fw.write("""  },\n
                                },\n""")
                        fw.write("PlaneTrack%dTrack2XYPath%dY = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[2][1]))
                        fw.write("""  },\n
                                },\n""")
                        
                        fw.write("PlaneTrack%dTrack3XYPath%dX = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[0][0]))
                        fw.write("""  },\n
                                },\n""")
                        fw.write("PlaneTrack%dTrack3XYPath%dY = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[0][1]))
                        fw.write("""  },\n
                                },\n""")                    
                        
                        fw.write("PlaneTrack%dTrack4XYPath%dX = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[1][0]))
                        fw.write("""  },\n
                                },\n""")
                        fw.write("PlaneTrack%dTrack4XYPath%dY = BezierSpline {" %(i,i))
                        fw.write("""SplineColor = { Red = 0, Green = 255, Blue = 0, },
                            NameSet = true,
                            KeyFrames = {
                        """)
                        for j, marker in enumerate(track.markers):
                            fw.write("  [%d] = { %s, Flags = { Linear = true, }, },\n" %(j, marker.corners[1][1]))
                        fw.write("""  },\n
                                },\n""")
                        
                        
                        fw.write("""
                                Tracker2 = Tracker {
                                    Trackers = {
                                        """)    
                        fw.write("""{
                                        PatternTime = 1,
                                        PatternX = 0.392840626111704,
                                        PatternY = 0.699857685009488,
                                    },\n
                                    {
                                        PatternTime = 1,
                                        PatternX = 0.392840626111704,
                                        PatternY = 0.699857685009488,
                                    },\n
                                    {
                                        PatternTime = 1,
                                        PatternX = 0.392840626111704,
                                        PatternY = 0.699857685009488,
                                    },\n
                                    {
                                        PatternTime = 1,
                                        PatternX = 0.392840626111704,
                                        PatternY = 0.699857685009488,
                                    },\n
                                    """)
                                    
                        fw.write("""},
                                    CtrlWZoom = false,
                                    Inputs = {TrackerList = Input { Value = 2, },""")
                        
                        fw.write("Name1 = Input { Value = \"PlaneTrack1\", }," )
                        fw.write("PatternCenter1 = Input { Value = { %r, %r, }, },"%( marker.corners[0][0],marker.corners[0][1]))
                        fw.write("PatternWidth1 = Input { Value = 0.0154571326929918, },")
                        fw.write("PatternHeight1 = Input { Value = 0.020841239721695, },")
                        fw.write("SearchWidth1 = Input { Value = 0.0574350764852365, },")
                        fw.write("SearchHeight1 = Input { Value = 0.0714421252371915, },")
                        fw.write("TrackedCenter1 = Input {" )
                        fw.write("SourceOp = \"PlaneTrack%dTrack1XYPath\"," %i)
                        fw.write("""Source = "Value",
                                        },
                                    """)
                        fw.write("Name2 = Input { Value = \"PlaneTrack2\", }," )
                        fw.write("PatternCenter2 = Input { Value = { %r, %r, }, },"%( marker.corners[1][0],marker.corners[1][1]))
                        fw.write("PatternWidth2 = Input { Value = 0.0154571326929918, },")
                        fw.write("PatternHeight2 = Input { Value = 0.020841239721695, },")
                        fw.write("SearchWidth2 = Input { Value = 0.0574350764852365, },")
                        fw.write("SearchHeight2 = Input { Value = 0.0714421252371915, },")
                        fw.write("TrackedCenter2 = Input {" )
                        fw.write("SourceOp = \"PlaneTrack%dTrack2XYPath\"," %i)
                        fw.write("""Source = "Value",
                                        },
                                    """)
                                    
                        fw.write("Name3 = Input { Value = \"PlaneTrack3\", }," )
                        fw.write("PatternCenter3 = Input { Value = { %r, %r, }, },"%( marker.corners[2][0],marker.corners[2][1]))
                        fw.write("PatternWidth3 = Input { Value = 0.0154571326929918, },")
                        fw.write("PatternHeight3 = Input { Value = 0.020841239721695, },")
                        fw.write("SearchWidth3 = Input { Value = 0.0574350764852365, },")
                        fw.write("SearchHeight3 = Input { Value = 0.0714421252371915, },")
                        fw.write("TrackedCenter3 = Input {" )
                        fw.write("SourceOp = \"PlaneTrack%dTrack3XYPath\"," %i)
                        fw.write("""Source = "Value",
                                        },
                                    """)
                        fw.write("Name4 = Input { Value = \"PlaneTrack4\", }," )
                        fw.write("PatternCenter4 = Input { Value = { %r, %r, }, },"%( marker.corners[3][0],marker.corners[3][1]))
                        fw.write("PatternWidth4 = Input { Value = 0.0154571326929918, },")
                        fw.write("PatternHeight4 = Input { Value = 0.020841239721695, },")
                        fw.write("SearchWidth4 = Input { Value = 0.0574350764852365, },")
                        fw.write("SearchHeight4 = Input { Value = 0.0714421252371915, },")
                        fw.write("TrackedCenter4 = Input {" )
                        fw.write("SourceOp = \"PlaneTrack%dTrack4XYPath\"," %i)
                        fw.write("""Source = "Value",
                                        },
                                    """)
                        
                        ##toolPosTracker = 1200+i*100
                        fw.write("ViewInfo = OperatorInfo { Pos = { %d, 100 } }," %toolPos)
                        fw.write("""
                                    },},""")
                        i += 1
        except:
            print("No clip found plane_track")
        
        # close composition
        fw.write("  },\n}\n")
        fw.close()
        print("finished export to fusion comp")


# ------------------------------------------------------------------------
#    Export Operator
# ------------------------------------------------------------------------

class EXPORT_OT_fusionComp(bpy.types.Operator, ExportHelper):
    """Save a python script which re-creates cameras and markers elsewhere"""
    bl_idname = "export_scene.fusion_comp"
    bl_label = "Export Fusion Composition"

    filename_ext = ".comp"
    
    filter_glob: bpy.props.StringProperty(
            default="*.comp", 
            options={'HIDDEN'}
        )

    frame_start: bpy.props.IntProperty(
            name="Start Frame",
            description="Start frame for export",
            default=1, 
            min=0, max=300000
        )
    
    frame_end: bpy.props.IntProperty(
            name="End Frame",
            description="End frame for export",
            default=250, 
            min=1, max=300000
        )
    
    only_selected: bpy.props.BoolProperty(
            name="Only Selected",
            default=False
        )

    def execute(self, context):
        write_cameras(context, self.filepath, self.frame_start, self.frame_end, self.only_selected)
        return {'FINISHED'}

    def invoke(self, context, event):
        self.frame_start = context.scene.frame_start
        self.frame_end = context.scene.frame_end

        wm = context.window_manager
        wm.fileselect_add(self)
        return {'RUNNING_MODAL'}


def draw_fusion_export_menu(self, context):
    default_path = os.path.splitext(bpy.data.filepath)[0] + ".comp"
    self.layout.operator(
            EXPORT_OT_fusionComp.bl_idname, 
            text="Fusion Composition (.comp)"
        ).filepath = default_path


# ------------------------------------------------------------------------
#    Registration
# ------------------------------------------------------------------------

def register():
    bpy.utils.register_class(EXPORT_OT_fusionComp)
    bpy.types.TOPBAR_MT_file_export.append(draw_fusion_export_menu)

def unregister():
    bpy.types.TOPBAR_MT_file_export.remove(draw_fusion_export_menu)
    bpy.utils.unregister_class(EXPORT_OT_fusionComp)


if __name__ == "__main__":
    register()