Пример #1
0
def refreshViewer():
    # Acquire original viewer and its active input
    viewer = nuke.activeViewer().node()
    acInput = nuke.activeViewer().activeInput()
    viewerName = viewer.name()
    print('Viewer data recorded.')

    for node in nuke.allNodes():
        node['selected'].setValue(0)
    viewer['selected'].setValue(1)  # Copy viewer only
    nukescripts.node_copypaste()
    print('Viewer duplicated.')

    newViewer = nuke.selectedNode()

    # Set new viewer's inputs to same as old
    inputs = range(viewer.inputs())
    for vInput in inputs:
        newViewer.setInput(vInput, viewer.input(vInput))
    print('Complete setting viewer\'s inputs')

    # Match old viewer's position and delete the old
    newViewer.setXYpos(viewer.xpos(), viewer.ypos())
    nuke.delete(viewer)
    print('Old viewer deleted.')
    # Rename new viewer to original
    newViewer['name'].setValue(viewerName)
    # Set active input to original
    nukescripts.connect_selected_to_viewer(acInput)
Пример #2
0
def holdAtFrame():
	node = nuke.selectedNode()
	node_label = node['label'].value()

	nukescripts.node_copypaste()  # Duplicating the Node
	print "\n\n", node.name()

	node_held = nuke.selectedNode()  # Return the duplicated node

	for name, k in node_held.knobs().items():
		try:
			if k.isAnimated():
				k.clearAnimated()
				print 'Deleting Animation on %s' % name
		except:
			print 'no animation to delete'

		node_held['tile_color'].setValue(2147418367)  # Light Green Color

		if node_label != "":  # for MPC Naming convnsion
			node_held['label'].setValue(node_label + "\n" + "x" + str(nuke.frame()))
		else:
			node_held['label'].setValue("x" + str(nuke.frame()))
Пример #3
0
def copyPostage():
    import nuke
    import nukescripts
    ###collecting data about connections
    g = nuke.selectedNodes()
    for n in g:
        if n.Class() == "PostageStamp" and n['hide_input'].value(
        ) == 1 or n.Class() == "Shuffle" and n['hide_input'].value(
        ) == 1 or n.Class() == "NoOp" and n['hide_input'].value() == 1:
            n['hide_input'].setValue(0)
            dep = n.dependencies(nuke.INPUTS)[0]
            n['hide_input'].setValue(1)
            lab = n['help'].setValue(dep['name'].value())

    ### standart copy paste
    count = 0
    for rr in g:
        count = count + 1
        x = int(rr['xpos'].value())
        y = int(rr['ypos'].value())
    nukescripts.node_copypaste()
    if count == 1:
        nuke.selectedNode().setXYpos(int(x - 100), int(y + 50))

    ####reconnecting postages
    e = nuke.selectedNodes()
    for n in e:
        if n.Class() == "PostageStamp" and n['hide_input'].value(
        ) == 1 or n.Class() == "Shuffle" and n['hide_input'].value(
        ) == 1 or n.Class() == "NoOp" and n['hide_input'].value(
        ) == 1 or n.Class() == "DeepExpression" and n['hide_input'].value(
        ) == 1:
            connect = nuke.toNode(n['help'].value())
            if connect not in g:
                n.setInput(0, connect)
                n['hide_input'].setValue(1)
Пример #4
0
def copyToProjector(node=None, frame=None, gui=nuke.GUI):
    if not node:
        node = nuke.thisNode()
    if not frame:
        frame = nuke.root()['frame'].value()

    if node.Class() not in ['StereoCam', 'StereoCam2', 'Camera', 'Camera2']:
        m = 'this node is not a supported camera type, unable to convert to projector'
        if gui:
            nuke.message(m)
        nuke.error(m)
        return

    saved_frame = nuke.root()['frame'].value()
    nuke.root()['frame'].setValue(frame)

    # Turn off all selected nodes, otherwise they mess up the node paste:
    for n in nuke.selectedNodes():
        n.knob('selected').setValue(False)

    # Now select this node then copy and paste it:
    node['selected'].setValue(True)
    nukescripts.node_copypaste()
    proj = nuke.selectedNode()

    # Name/label new node:
    new_name = 'projector_cam'
    if node.knob('shot') is not None:
        if node['shot'].getText() != '':
            new_name += '_%s_' % proj['shot'].getText().replace('.', '_')
    new_name += 'fr%d_' % nuke.frame()
    # De-duplicate the new name:
    counter = 1
    while 1:
        new_name2 = new_name + '%d' % counter
        if nuke.toNode(new_name2) is None:
            new_name = new_name2
            break
        counter += 1
    proj['name'].setValue(new_name)

    l = proj['label'].getText()
    if l != '' and not l.endswith('\\n'):
        l += '\\n'
    l += 'frame %d' % nuke.frame()
    proj['label'].setValue(l)

    # Offset its position in the DAG:
    xpos = node['xpos'].value()
    proj['xpos'].setValue(xpos + 100)
    ypos = node['ypos'].value()
    proj['ypos'].setValue(ypos + 100)

    # Unsplit all knobs (remove views):
    vs = nuke.views()
    if len(vs) > 1:
        for name, knob in proj.knobs().items():
            if issubclass(knob.__class__, nuke.Array_Knob):
                #print 'knob %s: unsplitting view %s' % (knob.name(), vs[1])
                knob.unsplitView(view=vs[1])

    # Clear animations from all knobs:
    for name, knob in proj.knobs().items():
        if knob.isAnimated():
            knob.clearAnimated()

    # Disable updating:
    if proj.knob('read_from_file') is not None:
        proj['read_from_file'].setValue(False)

    nuke.root()['frame'].setValue(saved_frame)
def silhouetteFxsExporter():
    '''
    Main exporter code, UI 
    '''
    try:
        rotoNode = nuke.selectedNode()
        if rotoNode.Class() not in ('Roto', 'RotoPaint'):
            if nuke.GUI:
                nuke.message(
                    'Unsupported node type. Selected Node must be Roto or RotoPaint'
                )
            return
    except:
        if nuke.GUI:
            nuke.message('Select a Roto or RotoPaint Node')
            return
    #===========================================================================
    # Nuke UI panel setup
    #===========================================================================
    p = nukescripts.panels.PythonPanel("FXS Shape Exporter")
    k = nuke.String_Knob("framerange", "FrameRange")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip(
        "Set the framerange to bake the shapes, by default its the project start-end. Example: 10-20"
    )
    p.addKnob(k)
    k.setValue("%s-%s" % (nuke.root().firstFrame(), nuke.root().lastFrame()))
    k = nuke.Boolean_Knob("bake", "Bake Shapes")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("Export the shapes baking keyframes and transforms")
    p.addKnob(k)
    result = p.showModalDialog()

    if result == 0:
        return  # Canceled
    try:
        fRange = nuke.FrameRange(p.knobs()["framerange"].getText())
    except:
        if nuke.GUI:
            nuke.message(
                'Framerange format is not correct, use startframe-endframe i.e.: 0-200'
            )
        return
    #===========================================================================
    # end of panel
    #===========================================================================
    start_time = time.time()
    rptsw_shapeList = []
    global cancel
    cancel = False

    if nuke.NUKE_VERSION_MAJOR > 6:
        #=======================================================================
        # creates a copy of the node to modify and keep original safe
        #=======================================================================
        nukescripts.node_copypaste()
        #=======================================================================
        bakeshapes = p.knobs()["bake"].value()
        rptsw_shapeList = []
        rotoNode = nuke.selectedNode()
        rotoCurve = rotoNode['curves']
        rotoRoot = rotoCurve.rootLayer
        #=*=*=*=*=*=*==task=related=code========================================
        task = nuke.ProgressTask('FXS Shape Exporter')
        task.setMessage('Starting FXS export')
        task.setProgress(10)
        #=*=*=*=*=*=*==task=related=code========================================
        rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)
        #=======================================================================
        # creates additional layers to handle shape transforms
        #=======================================================================
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Sorting out Transforms')
        task.setProgress(20)
        #=*=*=*=*=*=*==task=related=code========================================
        uniqueNames(rptsw_shapeList)
        if not bakeshapes:
            manageTransforms(fRange, rotoNode, rptsw_shapeList)  #,task)
        #=*=*=*=*=*=*==task=related=code========================================
        if cancel:
            return
        #=*=*=*=*=*=*==task=related=code========================================
        rotoCurve.changed()  #just for debugging purposes
        #=======================================================================
        rptsw_shapeList = []
        rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)
        nodeFormat = rotoNode['format'].value()
        fxsExport = ET.Element(
            'Silhouette', {
                'width': str(nodeFormat.width()),
                'height': str(nodeFormat.height()),
                'workRangeStart': str(fRange.first()),
                'workRangeEnd': str(fRange.last()),
                'sessionStartFrame': str(fRange.first())
            })
        #=======================================================================
        # create the root layer first
        #=======================================================================
        item = [rotoRoot, rotoRoot]
        createLayers(item, fRange, rotoNode, rptsw_shapeList, task, fxsExport,
                     bakeshapes)
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Creating Layers')
        task.setProgress(30)
        taskLength = len(rptsw_shapeList)
        taskCount = 0.0
        #=*=*=*=*=*=*==task=related=code========================================
        #=======================================================================
        # create all layers and shapes inside them
        #=======================================================================
        for item in rptsw_shapeList:
            taskCount += 1.0
            x = (taskCount / taskLength) * 10 + 30
            task.setProgress(30 + int((taskCount / taskLength) * 20))
            #=*=*=*=*=*=*==task=related=code========================================
            if cancel:
                break
            #=*=*=*=*=*=*==task=related=code========================================
            if isinstance(item[0], nuke.rotopaint.Layer):
                createLayers(item, fRange, rotoNode, rptsw_shapeList, task,
                             fxsExport, bakeshapes)
        #===================================================================
        # reorder layers/shapes
        #===================================================================
        layerlist = []
        for item in rptsw_shapeList[::-1]:
            if item[1].name not in layerlist:  #find all parent names
                layerlist.append(item[1].name)
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Reordering Layer/Shapes')
        task.setProgress(50)
        taskLength = len(rptsw_shapeList)
        taskCount = 0.0
        #=*=*=*=*=*=*==task=related=code========================================
        for name in layerlist:
            #=*=*=*=*=*=*==task=related=code========================================
            task.setProgress(50 + int((taskCount / taskLength) * 50))
            taskCount += 1.0
            if cancel:
                break
            #=*=*=*=*=*=*==task=related=code========================================
            data = []
            parentElement = []
            for item in rptsw_shapeList[::-1]:
                if item[1].name == name:  #all items from same parent
                    for itemx in fxsExport.findall('.//*'):
                        if itemx.get('label') != None:
                            if item[0].name == itemx.get('label'):
                                if itemx not in data:
                                    data.append(
                                        itemx
                                    )  #locate the elements of that parent
            for itemx in fxsExport.findall('.//*'):
                if itemx.get('label') == name:
                    obj = itemx.findall("Properties/Property")
                    for item in obj:
                        if item.get('id') == "objects":
                            parentElement.append(item)
                            break
            for n in range(len(data)):
                parentElement[0][n] = data[n]
        #===================================================================
        # end of reorder layers/shapes
        #===================================================================
    else:
        nuke.message('Shape Exporter is for Nuke v7 only')

    #=*=*=*=*=*=*==task=related=code========================================
    if cancel:
        nuke.delete(rotoNode)
        return
    #=*=*=*=*=*=*==task=related=code========================================

    #===========================================================================
    # EXPORT the fxs file
    #===========================================================================
    path = os.getenv('FXSEXPORTPATH')
    if path == None:
        path = nuke.getFilename('Save the .fxs file', '*.fxs', "fxsExport.fxs")
        if path == None:
            if nuke.GUI:
                nuke.message(
                    'Aborting Script, you need to save the export to a file')
                return
        else:
            base = os.path.split(path)[0]
            ext = os.path.split(path)[1][-4:]
            #==================================================================
            # adds extension if not present on the filename
            #==================================================================
            if ext != ".fxs":
                ext = ext + ".fxs"
                path = os.path.join(base, ext)
    else:
        print "Saving file to: %s" % path

    indent(fxsExport)
    ET.ElementTree(fxsExport).write(path)
    nuke.delete(rotoNode)
    task.setProgress(100)
    print "Time elapsed: %s seconds" % (time.time() - start_time)
Пример #6
0
def copyConnected():
    ### group the selected nodes
    selNodes = nuke.selectedNodes()

    ### we start the per node loop
    for node in selNodes:

        ### original list with dependencies to check if the node is connected
        dep = node.dependencies(nuke.INPUTS | nuke.HIDDEN_INPUTS)

        ### condition if the list is not empty (unconnected node)
        if dep:

            ### creates empty dict where we will add our inputs and connected nodes
            depDict = {}

            ## we get the number of inputs connected and we create a list with the range
            inputMax = node.inputs()
            inputRange = range(0, inputMax)

            ### we loop per input and store the name of the node connected to it (the if statement is in case there connection is empty it will do nothing)
            for inputCon in inputRange:
                inputNode = node.input(inputCon)
                if inputNode:
                    nodename = inputNode['name'].value()
                    depDict[inputCon] = nodename

            ### we check if our node selected is a wired or anchor node (trixter only)
            if node.knob('connection'):
                connection = node.knob('connection').getValue()

            ### we create the temp knobs with the dictionary of inputs and nodes (if the node is connected of course)
            else:
                tempTab = nuke.Tab_Knob('temp_tab', 'temp tab')
                node.addKnob(tempTab)
                depDictStr = str(depDict)
                tempText = nuke.Text_Knob('connectionTemp', 'connected to: ',
                                          depDictStr)
                node.addKnob(tempText)

    ### copy paste the nodes
    nukescripts.node_copypaste()

    ### group the new nodes created that are selected by default
    newNodes = nuke.selectedNodes()

    ### start of the loop for the new nodes
    for node in newNodes:

        ### we check if our node selected is a wired or anchor node (trixter only) and connects it to its input if the input is not duplicated
        if node.knob('connection'):
            anchor = node['connection'].value()
            inputNode = nuke.toNode(anchor)
            if inputNode not in selNodes:
                node.setInput(0, inputNode)

        ### we retrieve the dict knob and set it as dictionary
        elif node.knob('connectionTemp'):
            anchorStr = node['connectionTemp'].value()
            anchorDict = eval(anchorStr)

            ### for every key we retrieve the value of the dict
            for key in anchorDict:
                element = anchorDict[key]
                ### important f**k up, i don't know why nuke does not like the string resultant so i force the evaluation
                #evalInput = eval(element)

                ### we connect to the original input if it is not copied (selNodes) using the key (input number) and the value (node)
                inputNode = nuke.toNode(element)
                if inputNode not in selNodes:
                    node.setInput(key, inputNode)

            ### deletes the temp knobs from new nodes
            knobs = node.knobs()
            node.removeKnob(knobs['connectionTemp'])
            node.removeKnob(knobs['temp_tab'])

        ### we delete the variable count so it does'nt pile up
        # if 'count' in locals():
        #     del count

    ### deletes the temp knobs from old selected nodes
    for node in selNodes:
        if node.knob('connectionTemp'):
            node.hideControlPanel()
            allknobs = node.knobs()
            node.removeKnob(allknobs['connectionTemp'])
            node.removeKnob(allknobs['temp_tab'])
Пример #7
0
def silhouetteFxsExporter():
    '''
    Main exporter code, UI 
    '''
    try:
        rotoNode = nuke.selectedNode()
        if rotoNode.Class() not in ('Roto', 'RotoPaint'):
            if nuke.GUI:
                nuke.message( 'Unsupported node type. Selected Node must be Roto or RotoPaint' )
            return
    except:
        if nuke.GUI:
            nuke.message('Select a Roto or RotoPaint Node')
            return
    #===========================================================================
    # Nuke UI panel setup
    #===========================================================================
    p = nukescripts.panels.PythonPanel("FXS Shape Exporter")
    k = nuke.String_Knob("framerange","FrameRange")
    k.setFlag(nuke.STARTLINE)    
    k.setTooltip("Set the framerange to bake the shapes, by default its the project start-end. Example: 10-20")
    p.addKnob(k)
    k.setValue("%s-%s" % (nuke.root().firstFrame(), nuke.root().lastFrame()))    
    k = nuke.Boolean_Knob("bake", "Bake Shapes")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("Export the shapes baking keyframes and transforms")
    p.addKnob(k)
    result = p.showModalDialog()    
 
    if result == 0:
        return # Canceled
    try:
        fRange = nuke.FrameRange(p.knobs()["framerange"].getText())
    except:
        if nuke.GUI:
            nuke.message( 'Framerange format is not correct, use startframe-endframe i.e.: 0-200' )
        return
    #===========================================================================
    # end of panel
    #===========================================================================
    start_time = time.time()
    rptsw_shapeList = []
    global cancel
    cancel = False
    
    if nuke.NUKE_VERSION_MAJOR > 6:
        #=======================================================================
        # creates a copy of the node to modify and keep original safe
        #=======================================================================
        nukescripts.node_copypaste()
        #=======================================================================       
        bakeshapes =  p.knobs()["bake"].value() 
        rptsw_shapeList = []
        rotoNode = nuke.selectedNode()
        rotoCurve = rotoNode['curves']
        rotoRoot = rotoCurve.rootLayer
        #=*=*=*=*=*=*==task=related=code========================================
        task = nuke.ProgressTask('FXS Shape Exporter')
        task.setMessage('Starting FXS export')
        task.setProgress(10)
        #=*=*=*=*=*=*==task=related=code========================================
        rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)  
        #=======================================================================
        # creates additional layers to handle shape transforms
        #=======================================================================
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Sorting out Transforms')
        task.setProgress(20)
        #=*=*=*=*=*=*==task=related=code========================================
        uniqueNames(rptsw_shapeList)
        if not bakeshapes:
            manageTransforms(fRange, rotoNode, rptsw_shapeList)#,task)
        #=*=*=*=*=*=*==task=related=code========================================
        if cancel:
            return
        #=*=*=*=*=*=*==task=related=code========================================
        rotoCurve.changed() #just for debugging purposes
        #=======================================================================
        rptsw_shapeList = []
        rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)  
        nodeFormat = rotoNode['format'].value()
        fxsExport = ET.Element('Silhouette',{'width':str(nodeFormat.width()),'height':str(nodeFormat.height()),'workRangeStart':str(fRange.first()),'workRangeEnd':str(fRange.last()),'sessionStartFrame':str(fRange.first())})
        #=======================================================================
        # create the root layer first
        #=======================================================================
        item = [rotoRoot,rotoRoot]
        createLayers(item,fRange, rotoNode, rptsw_shapeList,task, fxsExport,bakeshapes)
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Creating Layers')
        task.setProgress(30)
        taskLength = len(rptsw_shapeList)
        taskCount = 0.0
        #=*=*=*=*=*=*==task=related=code========================================
        #=======================================================================
        # create all layers and shapes inside them
        #=======================================================================
        for item in rptsw_shapeList:
            taskCount +=1.0
            x = (taskCount/taskLength)*10+30
            task.setProgress(30+int((taskCount/taskLength)*20))
            #=*=*=*=*=*=*==task=related=code========================================
            if cancel:
                break
            #=*=*=*=*=*=*==task=related=code========================================
            if isinstance(item[0], nuke.rotopaint.Layer):
                createLayers(item,fRange, rotoNode, rptsw_shapeList,task,fxsExport,bakeshapes)
        #===================================================================
        # reorder layers/shapes
        #===================================================================
        layerlist = []
        for item in rptsw_shapeList[::-1]:
            if item[1].name not in layerlist:#find all parent names
                layerlist.append(item[1].name)
        #=*=*=*=*=*=*==task=related=code========================================
        task.setMessage('Reordering Layer/Shapes')
        task.setProgress(50)
        taskLength = len(rptsw_shapeList)
        taskCount = 0.0
        #=*=*=*=*=*=*==task=related=code========================================
        for name in layerlist:
            #=*=*=*=*=*=*==task=related=code========================================
            task.setProgress(50+int((taskCount/taskLength)*50))
            taskCount +=1.0
            if cancel:
                break
            #=*=*=*=*=*=*==task=related=code========================================
            data = []
            parentElement = []
            for item in rptsw_shapeList[::-1]:
                if item[1].name == name: #all items from same parent
                    for itemx in fxsExport.findall('.//*'):
                        if itemx.get('label') != None:
                            if item[0].name == itemx.get('label'):
                                if itemx not in data:
                                    data.append(itemx) #locate the elements of that parent
            for itemx in fxsExport.findall('.//*'):
                if itemx.get('label') == name:
                    obj = itemx.findall("Properties/Property")
                    for item in obj:
                        if item.get('id') == "objects":
                              parentElement.append(item)
                              break
            for n in range(len(data)):
                parentElement[0][n] = data[n]
        #===================================================================
        # end of reorder layers/shapes
        #===================================================================
    else:
        nuke.message( 'Shape Exporter is for Nuke v7 only' )

    #=*=*=*=*=*=*==task=related=code========================================
    if cancel:
        nuke.delete(rotoNode)
        return
    #=*=*=*=*=*=*==task=related=code========================================

    #===========================================================================
    # EXPORT the fxs file
    #===========================================================================
    path = os.getenv('FXSEXPORTPATH')
    if path == None:
         path = nuke.getFilename('Save the .fxs file', '*.fxs',"fxsExport.fxs")
         if path == None:
             if nuke.GUI:
                 nuke.message('Aborting Script, you need to save the export to a file' ) 
                 return
         else:
             base = os.path.split(path)[0]
             ext = os.path.split(path)[1][-4:]
             #==================================================================
             # adds extension if not present on the filename
             #==================================================================
             if ext != ".fxs": 
                 ext = ext + ".fxs"
                 path =  os.path.join(base,ext)
    else:
        print "Saving file to: %s" % path 

    indent(fxsExport)
    ET.ElementTree(fxsExport).write(path)
    nuke.delete(rotoNode)
    task.setProgress(100)  
    print "Time elapsed: %s seconds" % (time.time() - start_time)
def freezeWarp_v2():   
    try:
        node = nuke.selectedNode()
        if node.Class() not in ('SplineWarp3'):
            if nuke.GUI:
                nuke.message( 'Unsupported node type. Node must be SplineWarp' )
            return
    except:
        if nuke.GUI:
            nuke.message('Select a SplineWarp Node')
            return

    shapeList = []    
    curves = node['curves']
    nodeRoot = curves.rootLayer
    shapeList = fws_walker(nodeRoot, shapeList)
    
    #===========================================================================
    # panel setup
    #===========================================================================
    p = nukescripts.panels.PythonPanel("Freeze Splinewarp")
    k = nuke.Int_Knob("freezeframe","Freezeframe")
    k.setFlag(nuke.STARTLINE)    
    k.setTooltip("Set the frame to freeze the shapes positions")
    p.addKnob(k)
    k.setValue(nuke.root().firstFrame())
    k = nuke.Enumeration_Knob( 'outputcurve', 'Curves to Freeze', ['A', 'B'])
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("Freeze all the curves on the A or B output")
    p.addKnob(k)
    
    k = nuke.Boolean_Knob("mt", "MultiThread")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("This will speed up the script but without an accurate progress bar")
    p.addKnob(k)
    k.setValue(True)
    k = nuke.Boolean_Knob("exp", "Use Expression to Freeze")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("Instead of deleting keyframes, it will use expressions on the shapes and also add a frame control on the node")
    p.addKnob(k)
    k.setValue(True)
    k = nuke.Boolean_Knob("fh", "Create FrameHold")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("This will create a Framehold Node and set it to the Freezeframe value, if you use expressions mode it will be linked")
    p.addKnob(k)
    k.setValue(True)
    k = nuke.Boolean_Knob("stb", "Stabilize Setup")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("This will create a handy warp stabilization setup")
    p.addKnob(k)
    k.setValue(False)
    
    if not checkAB(shapeList):        
        p.addKnob( nuke.Text_Knob("","",'\n<b><font color="red">WARNING: your node has only<br>curves on A or B outputs</font></b>\n')) 
    
    
    #===========================================================================
    # end of panel setup
    #===========================================================================
    result = p.showModalDialog()    
    if result == 0:
        return # Canceled


    freezeFrame = p.knobs()["freezeframe"].value()
    ab = 1.0 if p.knobs()["outputcurve"].value() == "A" else 2.0
    exp = p.knobs()["exp"].value()
    mt = p.knobs()["mt"].value()
    if nuke.NUKE_VERSION_MAJOR > 6:
        #=======================================================================
        # task setup
        #=======================================================================
        global cancel
        cancel = False
        task = nuke.ProgressTask( 'Freeze SplineWarp' )
        n = 0
        #=======================================================================
        # task end
        #=======================================================================
        if exp:
            names = []
            for i in node.allKnobs():
                names.append(i.name())
            if "FreezeFrame" not in names: #avoid creating the pane if it already exists
                tab = nuke.Tab_Knob('FreezeFrame') 
                node.addKnob(tab)
                ff = nuke.Int_Knob('fframe',"Freeze Frame")
                node.addKnob(ff)
                try:
                    ff.setValue(freezeFrame)
                except:
                    pass

            for shape in shapeList:
                if cancel:
                    return
                task.setMessage('Processing ' + shape.name)
                task.setProgress((int(n/len(shapeList)*100)))
                if mt and nuke.NUKE_VERSION_MAJOR != 11:
                    threading.Thread(None,expressionLock, args=(shape,ab,freezeFrame,node,task)).start() 
                else:
                    expressionLock(shape,ab,freezeFrame,node,task)
                n+=1
        else:
            for shape in shapeList:
                if cancel:
                    return
                task.setMessage('Processing ' + shape.name)
                task.setProgress((int(n/len(shapeList)*100)))
                if mt:
                    threading.Thread(None,keyFreeze, args=(shape,ab,freezeFrame,task)).start() 
                else:
                    keyFreeze(shape,ab,freezeFrame,task)
                n+=1
                
        #===========================================================================
        #  join existing threads (to wait completion before continue)
        #===========================================================================
        if mt and nuke.NUKE_VERSION_MAJOR != 11:
            main_thread = threading.currentThread()
            for t in threading.enumerate():
                if t is main_thread:
                    continue
                t.join()

        curves.changed()
    else:
        nuke.message( 'This version is for Nuke v7, use v1.1 with Nuke v6.3 from Nukepedia' ) 

    #===========================================================================
    # framehold creation
    #=========================================================================== 
    fh = p.knobs()["fh"].value()
    if fh:
        framehold = nuke.nodes.FrameHold()
        if exp:
            framehold["first_frame"].setExpression(node.name() + ".fframe")

        else:
            framehold.knob("first_frame").setValue(freezeFrame)
        #=======================================================================
        # some layout beautyfication
        #=======================================================================
        framehold["xpos"].setValue(node["xpos"].getValue() - 100)
        framehold["ypos"].setValue(node["ypos"].getValue() - 80)
        dot = nuke.nodes.Dot()
        dot["xpos"].setValue(node["xpos"].getValue()+35)
        dot["ypos"].setValue(framehold["ypos"].getValue()+11)
        set_inputs(node,dot)
        set_inputs(dot,framehold)
        
    #=======================================================================
    # stabilization setup
    #=======================================================================
    stb = p.knobs()["stb"].value()
    if stb:
        nukescripts.node_copypaste()
        b_input = nuke.selectedNode()
        nukescripts.node_copypaste()
        a_input = nuke.selectedNode()
        b_input["mix"].setValue(1)
        dot = nuke.nodes.Dot()
        dot["label"].setValue("Stabilization")
        set_inputs(a_input,b_input)
        set_inputs(b_input,dot)
        nukescripts.swapAB(b_input)
        dot["xpos"].setValue(node["xpos"].getValue()+135)
        dot["ypos"].setValue(framehold["ypos"].getValue()+11)
        b_input["xpos"].setValue(node["xpos"].getValue()+135)
        b_input["ypos"].setValue(dot["ypos"].getValue()+80)
        a_input["xpos"].setValue(node["xpos"].getValue()+135)
        a_input["ypos"].setValue(dot["ypos"].getValue()+160)
        #=======================================================================
        # workaround.... if node is not show on properties tab the "root warp" attribute will not change!
        #=======================================================================
        b_input.knob('selected').setValue(True)
        nuke.show(nuke.selectedNode())
        nuke.selectedNode()["root_warp"].setValue(0)
  
    
    label = "FreezeF: [value fframe]" if exp else "FreezeF:" + str(freezeFrame)
    node.knob('label').setValue(label)
    node.knob('filter').setValue('Mitchell') #less smoother than cubic
    print "FreezeSplineWarp Finished,", len(shapeList), "shape(s) at frame", freezeFrame 
def Roto_to_WarpSpline_v2():
    try:
        rotoNode = nuke.selectedNode()
        if rotoNode.Class() not in ('Roto', 'RotoPaint'):
            if nuke.GUI:
                nuke.message( 'Unsupported node type. Selected Node must be Roto or RotoPaint' )
            return
    except:
        if nuke.GUI:
            nuke.message('Select a Roto or RotoPaint Node')
            return
    #===========================================================================
    # panel setup
    #===========================================================================
    p = nukescripts.panels.PythonPanel("RotoPaint to Splinewarp")
    k = nuke.String_Knob("framerange","FrameRange")
    k.setFlag(nuke.STARTLINE)    
    k.setTooltip("Set the framerange to bake the shapes, by default its the project start-end. Example: 10-20")
    p.addKnob(k)
    k.setValue("%s-%s" % (nuke.root().firstFrame(), nuke.root().lastFrame()))    
    k = nuke.Boolean_Knob("pin", "Break into Pin Points")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("This will break all the shapes into single points")
    p.addKnob(k)
    k = nuke.Boolean_Knob("mt", "MultiThread")
    k.setFlag(nuke.STARTLINE)
    k.setTooltip("This will speed up the script but without an accurate progress bar")
    p.addKnob(k)
    k.setValue(True)
    result = p.showModalDialog()    

    
    if result == 0:
        return # Canceled
    try:
        fRange = nuke.FrameRange(p.knobs()["framerange"].getText())
    except:
        if nuke.GUI:
            nuke.message( 'Framerange format is not correct, use startframe-endframe i.e.: 0-200' )
        return
    breakintopin = p.knobs()["pin"].value()
    multi = p.knobs()["mt"].value()
    #===========================================================================
    # end of panel
    #===========================================================================
    start_time = time.time()
#     task = nuke.ProgressTask('Roto to SplineWarp')
    rptsw_shapeList = []
    global cancel
    cancel = False
    if nuke.NUKE_VERSION_MAJOR > 6:
#         global cancel
        rptsw_shapeList = []
        nukescripts.node_copypaste()
        rotoNode = nuke.selectedNode()
        warpNode = nuke.createNode('SplineWarp3')
        warpNode.setName(rotoNode.name()+ "_" +  warpNode.name())
        warpCurve = warpNode['curves']
        warpRoot = warpCurve.rootLayer   
        rotoCurve = rotoNode['curves']
        rotoRoot = rotoCurve.rootLayer
        rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)  
        if breakintopin:
            breakshapesintoPin(rotoNode,fRange)  
            rptsw_shapeList = []
            rptsw_shapeList = rptsw_walker(rotoRoot, rptsw_shapeList)
        if cancel:
            return
        threadlist =[]
        n=0
        task = nuke.ProgressTask( 'Roto to SplineWarp' )
        bar = len(rptsw_shapeList) + 1
        for shape in rptsw_shapeList:
            if isinstance(shape[0], nuke.rotopaint.Shape):
                if multi and nuke.NUKE_VERSION_MAJOR != 11:
                    task.setMessage( 'Processing' + shape[0].name )
                    task.setProgress((int(n/bar*100)))
                    threading.Thread(None, bakeShapes, args=(shape, warpNode, fRange, rotoRoot, rptsw_shapeList, task)).start() 
                else:
                    bakeShapes(shape, warpNode,fRange, rotoRoot, rptsw_shapeList,task)
            n+=1
            
        #===========================================================================
        #  join existing threads (to wait completion before continue)
        #===========================================================================
        if multi and nuke.NUKE_VERSION_MAJOR != 11:
            main_thread = threading.currentThread()
            for t in threading.enumerate():
                if t is main_thread:
                    continue
                t.join()
            
        warpCurve.changed()
        warpNode.knob('toolbar_output_ab').setValue(1)
        warpNode.knob('boundary_bbox').setValue(0)
        #=======================================================================
        # theres a bug on Nuke 8 where the splinewarpnode UI do not update correctly with python created curves
        # this is a workaround
        #=======================================================================
        nukescripts.node_copypaste()
        nuke.show(nuke.selectedNode())
        nuke.selectedNode().knob('selected').setValue(False)
        #=======================================================================
        # end of workaround -
        #=======================================================================
        rptsw_shapeList = []
        nuke.delete(rotoNode)
        nuke.delete(warpNode)

    else:
        nuke.message( 'This version is for Nuke v7, use v1.1 with Nuke v6.3 from Nukepedia' )
    rptsw_shapeList = []
    if cancel:
        nuke.undo()
    print "Time elapsed:",time.time() - start_time, "seconds"