class AssetCloner:
    def __init__(self):
        self.project = Project()

    def clone(self):
        asset_list = self.project.list_assets_short()

        self.item_gui = sfl.SelectFromList(l=asset_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select an asset to clone")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        print("Selected asset: " + value[0])
        filename = value[0]

        self.body = Project().get_body(filename)
        self.element = self.body.get_element(Asset.USD)
        if self.element:
            path = self.element.get_last_publish()[3]
            if path:
                ref = hou.node("/stage").createNode("reference")
                ref.setName(filename + "_ref", 1)
                ref.parm("filepath1").set(path)
                ref.parm("primpath").set("/layout/" + filename)

        else:
            qd.error("Nothing was cloned")
    def solaris_asset_results(self, value):
        self.asset_name = value[0]

        body = Project().get_asset(self.asset_name)
        if not body:
            body = Project().create_asset(self.asset_name)
        if not body:
            qd.error("Something broke :'(")
            return
        self.element = body.get_element(Asset.USD)
        self.path = os.path.join(self.element._filepath, "temp.usda")

        selection = hou.selectedNodes()
        if len(selection) != 1:
            qd.error(
                "Please select the last node in the network and try again.")
            return

        out = selection[0]

        rop = hou.node("/stage").createNode("usd_rop")
        rop.setInput(0, out)
        rop.parm("lopoutput").set(self.path)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        rop.parm("execute").pressButton()
    def results(self, value):
        self.asset_name = value[0]

        body = Project().get_asset(self.asset_name)
        if not body:
            body = self.project.create_asset(self.asset_name)
        if not body:
            qd.error("Something broke :'(")
            return
        self.element = body.get_element(Asset.USD)
        self.path = os.path.join(self.element._filepath, "temp.usda")

        selection = hou.selectedNodes()
        if len(selection) != 1:
            qd.error("Please select the last node in the network and try again.")
            return
        
        out = selection[0]

        rop = hou.node("/stage").createNode("usd_rop")
        rop.setInput(0, out)
        rop.parm("lopoutput").set(self.path)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        rop.parm("execute").pressButton()

        rop.destroy()

        publishes = self.element.list_publishes()
        publishes_string_list = ""
        for publish in publishes:
            label = publish[0] + " " + publish[1] + " " + publish[2] + "\n"
            publishes_string_list += label

        self.input = qd.HoudiniInput(parent=hou.qt.mainWindow(), title="Comment ", info=publishes_string_list)
        self.input.submitted.connect(self.comment_results)
    def results(self, value):
        self.asset_name = value[0]

        body = Project().get_asset(self.asset_name)
        if not body:
            body = self.project.create_asset(self.asset_name)
        if not body:
            qd.error("Something broke :'(")
            return
        self.element = body.get_element(Asset.GEO)
        self.usdElem = body.get_element(Asset.GEO)
        path = self.element._filepath

        selectedNodes = hou.selectedNodes()
        if len(selectedNodes) != 1:
            qd.error("Select one node to publish its geometry")
            return
        geo = selectedNodes[0]
        if geo.type().name() != "geo":
            qd.error("You can only publish from geo nodes")
            return

        for child in geo.children():
            if child.isDisplayFlagSet():
                #print("hello there from " + child.name())
                cache = geo.createNode("filecache")
                cache.setInput(0, child)
                usd = geo.createNode("usdexport")
                usd.setInput(0, child)

                cache.parm("filemode").set(2)
                cache.parm("file").set(os.path.join(path, "temp.obj"))
                cache.parm("trange").set(0)
                cache.parm("execute").pressButton()

                usd.parm("authortimesamples").set("Never")
                usd.parm("lopoutput").set(os.path.join(path, "temp.usda"))
                usd.parm("execute").pressButton()

                usd.destroy()
                cache.destroy()

                publishes = self.element.list_publishes()
                publishes_string_list = ""
                for publish in publishes:
                    label = publish[0] + " " + publish[1] + " " + publish[
                        2] + "\n"
                    publishes_string_list += label

                self.input = qd.HoudiniInput(parent=hou.qt.mainWindow(),
                                             title="Comment ",
                                             info=publishes_string_list)
                self.input.submitted.connect(self.comment_results)
    def getFilePath(self, name):
        asset = Project().get_asset(name)
        path = asset.get_filepath()
        path = os.path.join(path, Asset.RIG)

        self.element = asset.get_element(Asset.RIG)

        path = os.path.join(path, name)
        last_version = self.element.get_last_version()
        current_version = last_version + 1
        path = path + "_v" + str(current_version).zfill(3) + ".mb"
        print(path)
        return path
class GeoCloner:
    def __init__(self):
        self.project = Project()

    def clone(self):
        asset_list = self.project.list_existing_assets()

        self.item_gui = sfl.SelectFromList(l=asset_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select an asset to clone")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        print("Selected asset: " + value[0])
        filename = value[0]

        self.body = Project().get_body(filename)
        self.element = self.body.get_element(Asset.GEO)
        if self.element:
            #just reference in the asset, make sure we're referencing the usda geo
            path = self.element.get_last_publish()[3]
            parts = path.split(".")
            path = parts[0] + ".usda"

            ref = hou.node("/stage").createNode("reference")
            ref.setName(filename + "_geo", 1)
            ref.parm("filepath1").set(path)

            #also clone into the geo context from the obj file
            parts = path.split(".")
            path = parts[0] + ".obj"
            geo = hou.node("/obj").createNode("geo")
            geo.setName(filename + "_geoRef", 1)
            geo.parm("scale").set(0.01)

            fileNode = geo.createNode("file")
            fileNode.parm("file").set(path)

        else:
            qd.error("Nothing was cloned")
class ShotCloner:
    def __init__(self):
        self.project = Project()

    def clone(self):
        shot_list = self.project.list_existing_shots()

        self.item_gui = sfl.SelectFromList(l=shot_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select a shot to clone")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        print("Selected shot: " + value[0])
        shot_name = value[0]

        self.body = Project().get_body(shot_name)
        self.element = self.body.get_element(Asset.HIP)
        if self.element.get_last_version() >= 0:
            #check if checked out
            if self.element.is_assigned():
                assigned_user = self.element.get_assigned_user()
                username = Environment().get_user().get_username()
                if not assigned_user == username:
                    qd.error("This shot is currently checked out by " +
                             assigned_user)
                    return
            else:
                username = Environment().get_user().get_username()
                self.element.update_assigned_user(username)

            path = self.element.get_last_publish()[3]
            if path:
                hou.hipFile.load(path)

        else:
            qd.error("Nothing was cloned")
class Publisher:
    def __init__(self):
        print("starting publisher")
        self.body = None
        self.fileName = None
        self.element = None

    def export_usd_files():
        # TODO: export usd from the whole asset node tree to the asset folder (same as .body)
        pass

    # command necessary for publish_asset dialog box to load correctly
    def set_new_version_button_command(self, node, version_window):
        """
        :param node: hou.Node
        :param version_window: VersionWindow
        :return: None
        """
        library_filepath = node.type().definition().libraryFilePath()
        name_base = '::'.join(node.type().name().split('::')[:-1])
        new_version = '{major}.{minor}.{revision}'.format(
            major=version_window.major_version.value(),
            minor=version_window.minor_version.value(),
            revision=version_window.revision_version.textFromValue(
                version_window.revision_version.value()))
        new_name = '{name_base}::{new_version}'.format(name_base=name_base,
                                                       new_version=new_version)
        # Here we can compare the current version to new version and detect if the new version is lower or equal
        if not StrictVersion(new_version) > StrictVersion(
                node.type().nameComponents()[-1]):
            hou.ui.displayMessage(
                'The version number is the same as the current version - please increase number'
            )
            return
        # Create a pop up to give the user a chance to confirm or cancel
        answer = hou.ui.displayMessage(
            'Creating a new version for {node_name}\nNew Version - {new_version}'
            .format(node_name=node.type().name(), new_version=new_version),
            title='Setting New Version',
            buttons=['OK', 'Cancel'])

        # If answer 'OK', create new version and set to latest version
        if answer == 0:
            node.type().definition().copyToHDAFile(library_filepath, new_name)
            all_definitions = hou.hda.definitionsInFile(library_filepath)
            node.changeNodeType(all_definitions[-1].nodeTypeName())
            # Close version window

    def publish_asset(self, solaris):
        '''
        this is what's called when the button is pushed.
        '''
        project = Project()

        asset_list = project.list_assets()
        self.item_gui = sfl.SelectFromList(l=asset_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select an asset to publish")
        # call asset results function here to be used once selected
        if solaris:
            self.item_gui.submitted.connect(self.solaris_asset_results)
        else:
            self.item_gui.submitted.connect(self.asset_results)

    def solaris_asset_results(self, value):
        self.asset_name = value[0]

        body = Project().get_asset(self.asset_name)
        if not body:
            body = Project().create_asset(self.asset_name)
        if not body:
            qd.error("Something broke :'(")
            return
        self.element = body.get_element(Asset.USD)
        self.path = os.path.join(self.element._filepath, "temp.usda")

        selection = hou.selectedNodes()
        if len(selection) != 1:
            qd.error(
                "Please select the last node in the network and try again.")
            return

        out = selection[0]

        rop = hou.node("/stage").createNode("usd_rop")
        rop.setInput(0, out)
        rop.parm("lopoutput").set(self.path)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        rop.parm("execute").pressButton()

    def asset_comment(self, value):
        comment = value[0]
        username = Environment().get_user().get_username()
        self.element.publish(username, self.path, comment, self.asset_name)

    def asset_results(self, value):
        self.fileName = value[0]
        selection = hou.selectedNodes()
        # If it is more than one or none, abort
        if len(selection) != 1:
            qd.error(
                'Please select a single Houdini Digital Asset node to save and update version on.'
            )
            return
        # If it is not a Houdini Digital Asset, abort
        if not selection[0].type().definition():
            qd.error(
                'Please select a single Houdini Digital Asset node to save and update version on.'
            )
            return

        #add code to force node name/node type name
        hda_node = selection[0]
        definition = hda_node.type().definition()
        libraryFilePath = definition.libraryFilePath()
        self.filepath = libraryFilePath
        '''current_full_name = hda_node.type().name()

        # last index is current version
        current_version_string = hda_node.type().nameComponents()[-1]
        #current_major = current_version_string.split('.')[0]
        #print('major version is ' + current_major)
        #current_minor = current_version_string.split('.')[1]
        # Set the 3 digit revision number to 0 if the HDA is only using the single float versioning (1.0 and not 1.0.005)
        current_revision = 0 if len(current_version_string.split(
            '.')) < 3 else current_version_string.split('.')[2]
        all_definitions = hou.hda.definitionsInFile(libraryFilePath)
        # This sets the node to the latest version of those stored
        hda_node.changeNodeType(all_definitions[-1].nodeTypeName())'''
        definition.updateFromNode(hda_node)

        self.body = Project().create_asset(self.fileName)
        if self.body is None:
            self.body = Project().get_asset(self.fileName)
        if self.body is None:
            print("Stephanie did an oopsie whoopsie :'(")
            return

        self.input = qd.HoudiniInput(parent=hou.qt.mainWindow(),
                                     title="Comment ")
        self.input.submitted.connect(self.comment_results)

    def comment_results(self, value):
        comment = str(value)
        path = os.path.join(self.body.get_filepath(), Asset.HDA)
        self.element = Element(path)

        username = Environment().get_user().get_username()

        name = self.fileName
        self.element.update_app_ext(".hda")
        self.element.publish(username, self.filepath, comment, name)
        # this bit will display the version info. Probably unneeded, as we'll be using element stuff instead.
        #f = open('/users/animation/martinje/Desktop/info.txt', 'r')
        #file_contents = f.read()
        # print(file_contents)
        # f.close()

        # qd.info(file_contents)

        # Instantiate the VersionWindow class - at this point, I would jump over to that code - keep in mind, we will
        # return a window object and afterwards we will set its initial state, using everything we just learned about
        # this HDA.

        #version_window = qd.VersionWindow(hou.qt.mainWindow())
        #version_window.setWindowTitle('Versioning for: {hda_name}'.format(hda_name=current_full_name))
        # version_window.current_version_label.setText(current_version_string)
        # version_window.current_path_label.setText(libraryFilePath)
        # Set value of the integer editor and set the editor to not go down from there
        # version_window.major_version.setValue(int(current_major))
        # version_window.major_version.setMinimum(int(current_major))
        # Set value of the integer editor and set the editor to not go down from there
        # version_window.minor_version.setValue(int(current_minor))
        # version_window.minor_version.setMinimum(int(current_minor))
        # Set value of the integer editor and set the editor to not go down from there
        # version_window.revision_version.setValue(int(current_revision))
        # version_window.revision_version.setMinimum(int(current_revision))
        # Connect the button signal to the set new version command and pass the hda node and the version window as arguments
        #version_window.set_version.clicked.connect(partial(self.set_new_version_button_command, hda_node, version_window))
        # Show the window
        # version_window.show()

    def publish_tool(self):
        pass

    def publish_shot(self):
        '''
        publishes shot (entire .hip file). Nothing needs to be selected for this to work.
        '''
        scene = hou.hipFile.name()
        print('file name is ' + scene)

        project = Project()  # get project and its shots
        asset_list = project.list_shots()

        self.item_gui = sfl.SelectFromList(
            l=asset_list,
            parent=hou.qt.mainWindow(),
            title="Select a shot to publish to, my friend.")
        self.item_gui.submitted.connect(self.shot_results)

    def shot_results(self, value):
        # chosen shot is the only asset in the list
        self.chosen_shot = value[0]

        self.comment = qd.HoudiniInput(parent=hou.qt.mainWindow(),
                                       title="Comments?")
        self.comment.submitted.connect(self.shot_comment)

    def shot_comment(self, value):
        # hou.hipFile.setName('newName_v01')  #this will change the name of the file: can be versioned. So that's nice.
        comment = value
        if comment is None:
            comment = "Publish by " + \
                str(user.get_username()) + \
                '. Ask them to leave a comment next time lol'
        # FIXME: make variable more specific to shot?
        chosen_shot = self.chosen_shot
        project = Project()

        print('Selected shot name: ' + chosen_shot)
        # print(project.get_body(chosen_shot))
        shot_body = project.create_shot(chosen_shot)
        if shot_body is None:
            shot_body = project.get_shot(chosen_shot)
        if shot_body is None:
            print("Something is horribly wrong. Talk to Stephanie")
            return
        filepath = shot_body.get_filepath()
        shot_element = shot_body.get_element("hip")
        shot_element.update_app_ext(".hip")
        prev_vers = shot_element.get_last_version()
        # path = os.path.abspath(inspect.getfile(project.get_body(chosen_shot)))      #trying to get path here.
        filepath = os.path.join(shot_element._filepath, chosen_shot + ".hip")
        #
        print('file path is ', filepath)
        hou.hipFile.setName(filepath)
        src = hou.hipFile.save()
        # # hou.hipFile.saveAndIncrementFileName()      #this actually works! Dunno if I want to use it though.
        #
        # #Publish
        user = Environment().get_user()
        pipeline_io.set_permissions(src)
        # try that asset name is body name.
        dst = self.publish_element(shot_element, user, filepath, comment)
        #pipeline_io.set_permissions(dst)
        #
        # message = "Successfully published " + str(self.body.get_name()) + "!"
        # self.print_success_message(message)

    def publish_element(self, element, user, src, comment="None"):
        print('username is', user.get_username())
        dst = element.publish(user.get_username(), src, comment,
                              self.chosen_shot)

        # Ensure file has correct permissions
        # Permissions are actually taken care of as part of the element.publish() function, so this isn't necessary
        '''try:
            os.chmod(dst, 0660)
        except Exception as e:
            print("Error setting file permissions: " + str(e))'''

        return dst

    def publish_layout(self):
        if len(hou.selectedNodes()) != 1:
            qd.error("Select only the last node in the network")
            return

        layout_list = Project().list_layouts()

        self.item_gui = sfl.SelectFromList(
            l=layout_list,
            parent=hou.qt.mainWindow(),
            title="Which layout are you publishing?")
        self.item_gui.submitted.connect(self.layout_results)

    def layout_results(self, value):
        self.layout_name = value[0]
        self.layout = Project().get_layout(self.layout_name)
        if self.layout is None:
            self.layout = Project().create_layout(self.layout_name)
        if self.layout is None:
            qd.error("Stephanie done messed up")
            return
        self.element = self.layout.get_element(Asset.LAYOUT)

        # make a USD ROP node
        rop = hou.node("/stage").createNode("usd_rop")
        # connect the selected node to the ROP
        out = hou.selectedNodes()[0]
        rop.setInput(0, out)
        # set the necessary values in the ROP
        self.savePath = os.path.join(self.element._filepath,
                                     self.layout_name + ".usda")
        rop.parm("lopoutput").set(self.savePath)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        # save to disk
        rop.parm("execute").pressButton()
        #add attributes to stage reqired for proper unpacking later
        self.create_attributes(out)
        # publish :)
        self.comment = qd.HoudiniInput(parent=hou.qt.mainWindow(),
                                       title="Comment for publish?")
        self.comment.submitted.connect(self.layout_comment)

    def create_attributes(self, node):
        stage = Usd.Stage.Open(self.savePath)

        node_list = []
        node_list = self.listInputs(node, node_list)

        for n in node_list:
            #create a ref_path attribute for each reference in the stage
            '''if n.type().name() == "reference":
                prim = stage.GetPrimAtPath(n.parm("primpath").eval())
                if prim.IsValid():
                    path = prim.CreateAttribute("ref_path", Sdf.ValueTypeNames.String)
                    path.Set(n.parm("filepath1").eval())
                else:
                    print("uh oh")'''

            #create a hda_path attribute for each material in the stage
            if n.type().name() == "materiallibrary":
                mats = n.children()
                for mat in mats:
                    if mat.type().definition():
                        print(mat.type().definition().libraryFilePath())
                        prim = stage.GetPrimAtPath(
                            n.parm("matpathprefix").eval() + mat.name())
                        if prim.IsValid():
                            path = prim.CreateAttribute(
                                "hda_path", Sdf.ValueTypeNames.String)
                            path.Set(mat.type().definition().libraryFilePath())
                        else:
                            print("hmmmmmmmqow;ugh")
                    else:
                        #send error message
                        qd.error(
                            "Material " + mat.name() +
                            " is not an HDA and won't load properly in the scene."
                        )

        stage.Save()

    def listInputs(self, n, list):
        list.append(n)
        inputs = n.inputs()
        for input in inputs:
            if input is not None:
                blank = []
                list.extend(self.listInputs(input, blank))
        return list

    def layout_comment(self, value):
        comment = value[0]
        username = Environment().get_user().get_username()
        self.element.update_app_ext(".usda")
        self.element.publish(username, self.savePath, comment,
                             self.layout_name)

        if self.element.get_last_version() == 0:
            # if it is the first publish, we have to make the referencing file as well
            # create a reference node
            ref = hou.node("/stage").createNode("reference")
            # set the values to reference the main publish file, etc.
            ref.parm("primpath").set("/layout")
            ref.parm("filepath1").set(self.element.get_last_publish()[3])
            # create a USD ROP node and connect it to the ref node
            refrop = hou.node("/stage").createNode("usd_rop")
            refrop.setInput(0, ref)
            # set the values in the ROP and save to disk alongside the main publish
            refrop.parm("lopoutput").set(
                os.path.join(self.element._filepath,
                             self.layout_name + "_ref.usda"))
            refrop.parm("enableoutputprocessor_simplerelativepaths").set(0)
            refrop.parm("execute").pressButton()
            #   this only needs to be done once since with every new publish, the file being referenced gets updated
            ref.destroy()
            refrop.destroy()
    def results(self, value):
        self.asset_name = value[0]

        body = Project().get_asset(self.asset_name)
        if not body:
            body = self.project.create_asset(self.asset_name)
        if not body:
            qd.error("Something broke :'(")
            return
        self.element = body.get_element(Asset.MATERIALS)

        self.path = os.path.join(self.element._filepath, "temp.usda")

        selection = hou.selectedNodes()
        if len(selection) != 1:
            qd.error("Please select only the material node and try again.")
            return
        shader = selection[0]
        if shader.type().name == "materiallibrary":
            qd.error(
                "Changes have been made to this publishing tool. Now you must select the material node itself, NOT the material library, to publish it. Please try again."
            )
            return

        #check where we are and move shader node accordingly
        deleteLib = False
        path = shader.path()
        first = path.split("/")[1]
        if first != "stage":
            lib = hou.node("/stage").createNode("materiallibrary")
            deleteLib = True
            shader = hou.copyNodesTo([shader], lib)[0]
        else:
            lib = shader.parent()

        lib.setInput(0, None)
        lib.parm("matpath1").set(value[0])

        #create and save material hda
        if shader.canCreateDigitalAsset():
            hdaPath = os.path.join(self.element._filepath,
                                   self.asset_name + "_main.hda")
            shader = shader.createDigitalAsset(name=re.sub(
                r'\W+', '', self.asset_name),
                                               description=self.asset_name,
                                               hda_file_name=hdaPath,
                                               min_num_inputs=0,
                                               max_num_inputs=0)
            shaderDef = shader.type().definition()
            shaderOptions = shaderDef.options()
            shaderOptions.setUnlockNewInstances(True)
            shaderOptions.setSaveInitialParmsAndContents(True)
            shaderDef.setOptions(shaderOptions)
            shaderDef.save(hdaPath, shader, shaderOptions)
        elif shader.type().name() == re.sub(r'\W+', '', self.asset_name):
            shader.type().definition().updateFromNode(shader)
            shader.type().definition().save(
                shader.type().definition().libraryFilePath())
        else:
            qd.error("Error creating/saving hda. Continuing to save USDA...")

        shader.setName(value[0])

        rop = hou.node("/stage").createNode("usd_rop")
        rop.setInput(0, lib)
        rop.parm("lopoutput").set(self.path)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)
        rop.parm("execute").pressButton()

        rop.destroy()
        if deleteLib:
            lib.destroy()

        publishes = self.element.list_publishes()
        publishes_string_list = ""
        for publish in publishes:
            label = publish[0] + " " + publish[1] + " " + publish[2] + "\n"
            publishes_string_list += label

        self.input = qd.HoudiniInput(parent=hou.qt.mainWindow(),
                                     title="Comment ",
                                     info=publishes_string_list)
        self.input.submitted.connect(self.comment_results)
class LayoutPublisher:

    def __init__(self):
        self.project = Project()

    def publish(self):
        if len(hou.selectedNodes()) != 1:
            qd.error("Select only the last node in the network")
            return

        layout_list = Project().list_layouts()

        self.item_gui = sfl.SelectFromList(l=layout_list, parent=hou.qt.mainWindow(), title="Which layout are you publishing?")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        self.layout_name = value[0]

        self.layout = self.project.get_layout(self.layout_name)
        if self.layout is None:
            self.layout = Project().create_layout(self.layout_name)
        if self.layout is None:
            qd.error("Stephanie done messed up")
            return

        self.element = self.layout.get_element(Asset.LAYOUT)

        rop = hou.node("/stage").createNode("usd_rop")

        out = hou.selectedNodes()[0]
        rop.setInput(0, out)

        self.savePath = os.path.join(self.element._filepath, self.layout_name + ".usda")
        rop.parm("lopoutput").set(self.savePath)
        rop.parm("enableoutputprocessor_simplerelativepaths").set(0)

        rop.parm("execute").pressButton()

        rop.destroy()

        publishes = self.element.list_publishes()
        publishes_string_list = ""
        for publish in publishes:
            label = publish[0] + " " + publish[1] + " " + publish[2] + "\n"
            publishes_string_list += label
        
        self.comment = qd.HoudiniInput(
            parent=hou.qt.mainWindow(), title="Comment for publish?", info=publishes_string_list)
        self.comment.submitted.connect(self.comment_results)

    def comment_results(self, value):
        comment = str(value)
        username = Environment().get_user().get_username()
        self.element.update_app_ext(".usda")
        self.element.publish(username, self.savePath, comment, self.layout_name)

        if self.element.get_last_version() == 0:
            # if it is the first publish, we have to make the referencing file as well
            # create a reference node
            ref = hou.node("/stage").createNode("reference")
            # set the values to reference the main publish file, etc.
            ref.parm("primpath").set("/layout")
            ref.parm("filepath1").set(self.element.get_last_publish()[3])          
            # create a USD ROP node and connect it to the ref node
            refrop = hou.node("/stage").createNode("usd_rop")
            refrop.setInput(0, ref)
            # set the values in the ROP and save to disk alongside the main publish
            refrop.parm("lopoutput").set(os.path.join(self.element._filepath, self.layout_name + "_ref.usda"))
            refrop.parm("enableoutputprocessor_simplerelativepaths").set(0)
            refrop.parm("execute").pressButton()

            pio.set_permissions(os.path.join(self.element._filepath, self.layout_name + "_ref.usda"))
            #   this only needs to be done once since with every new publish, the file being referenced gets updated
            ref.destroy()
            refrop.destroy()
class BuildShot:
    def __init__(self):
        self.project = Project()

    def build(self):
        shot_list = self.project.list_existing_shots()

        self.item_gui = sfl.SelectFromList(l=shot_list,
                                           parent=hou.ui.mainQtWindow(),
                                           title="Select a shot to clone")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        self.shot_name = value[0]
        self.shotBody = Project().get_body(self.shot_name)

        camElement = self.shotBody.get_element(Asset.CAMERA)
        asset_list = next(os.walk(camElement._filepath))[1]
        for name in asset_list:
            if name == "cache":
                asset_list.remove(name)
        asset_list.sort(key=unicode.lower)
        if len(asset_list) < 1:
            qd.error(
                "There is no camera for this shot, so it cannot be built. Quitting build for shot "
                + self.shot_name + "...")
        elif len(asset_list) == 1:
            self.camResults(asset_list)
        else:
            self.item_gui = sfl.SelectFromList(
                l=asset_list,
                parent=hou.ui.mainQtWindow(),
                title="Select a camera to clone")
            self.item_gui.submitted.connect(self.camera_results)

    def camResults(self, value):
        camName = value[0]
        self.camElement = self.shotBody.get_element(
            os.path.join(Asset.CAMERA, camName))
        options = ["Animation", "Layout", "Lights", "FX"]
        valueGui = qd.CheckboxSelect(
            text="Select what to import from this shot",
            options=options,
            parent=hou.ui.mainQtWindow(),
            title="Shot Build Settings")
        valueGui.submitted.connect(self.options_results)

    def options_results(self, options):
        '''for op in options:
            print(op)'''
        anim = options[0]
        layout = options[1]
        lights = options[2]
        fx = options[3]

        isCamera = self.get_camera()
        if not isCamera:
            return

        if anim:
            isAnim = self.get_all_anim()
            if not isAnim:
                qd.message(
                    "There is no animation published for this shot. Continuing to build shot..."
                )

        if layout:
            isLayout = self.get_layout()
            if not isLayout:
                qd.message(
                    "Couldn't clone the layout for this shot. Continuing to build shot..."
                )

        self.sequence_name = self.shot_name[:1]
        self.sequence = self.project.get_sequence(self.sequence_name)

        if lights:
            isLights = self.get_lights()
            if not isLights:
                qd.message(
                    "Couldn't clone sequence lighting. Continuing to build shot..."
                )

        if fx:
            self.get_fx()

        hou.node("/obj").layoutChildren()

        self.build_render()

    def get_camera(self):
        if self.camElement.get_last_version < 0:
            qd.error(
                "There is no camera for this shot, so it cannot be built. Quitting build for shot "
                + self.shot_name + "...")
            return False
        try:
            path = self.camElement.get_last_publish()[3]

            cameraNode = hou.node("/obj").createNode("cenoteCamera")
            cameraNode.setName(self.shot_name + "_camera", 1)
            cameraNode.parm("fileName").set(path)
            cameraNode.parm("scale").set(0.01)
            cameraNode.parm("buildHierarchy").pressButton()
            return True
        except Exception as e:
            print(e)
            return False

    def get_all_anim(self):
        animElement = self.shotBody.get_element(Asset.ANIMATION)
        asset_list = next(os.walk(animElement._filepath))[1]
        for name in asset_list:
            if name == "cache":
                asset_list.remove(name)
        asset_list.sort(key=unicode.lower)
        if len(asset_list) < 1:
            return False

        for asset in asset_list:
            self.get_anim(asset)
        return True

    def get_anim(self, asset):
        element = self.shotBody.get_element(
            os.path.join(Asset.ANIMATION, asset))
        if element.get_last_version() < 0:
            return False

        try:
            path = element.get_last_publish()[3]

            anim_cloner = AnimCloner()
            anim_cloner.asset_name = asset
            anim_cloner.build_network(path)
            return True

        except Exception as e:
            print(e)
            return False

    def get_layout(self):
        layout_element = self.shotBody.get_element(Asset.LAYOUT)
        path = os.path.join(layout_element._filepath, self.shot_name + ".usda")
        if not os.path.exists(path):
            print("Layout path doesn't exist")
            return False
        try:
            layoutUnpacker = LayoutUnpacker()
            layoutUnpacker.shot_name = self.shot_name
            layoutUnpacker.unpack(path)
            return True
        except Exception as e:
            print(e)
            return False

    def get_lights(self):
        lightElement = self.sequence.get_element(Asset.LIGHTS)
        if lightElement.get_last_version() < 0:
            return False

        path = lightElement.get_last_publish()[3]
        hou.hda.installFile(path)

        try:
            hda = hou.node("/obj").createNode("sequence_" +
                                              self.sequence_name + "_lights")
        except Exception as e:
            #qd.error("Couldn't create node of type " + name + ". You should still be able to tab in the node manually.")
            print(e)
            return False

        try:
            hda.setName(self.sequence_name + "_sequence_lights", 1)
        except:
            pass

        try:
            hda.allowEditOfContents()
        except:
            pass

        return True

    def get_fx(self):
        fxElement = self.sequence.get_element(Asset.HDA)
        fx_list = next(os.walk(fxElement._filepath))[1]
        for name in fx_list:
            if name == "cache":
                fx_list.remove(name)
        fx_list.sort(key=unicode.lower)

        for fx in fx_list:
            self.get_one_fx(fx)

    def get_one_fx(self, fx):
        element = self.sequence.get_element(os.path.join(Asset.HDA, fx))

        if element.get_last_version() < 0:
            return
        filepath = element.get_last_publish()[3]

        try:
            hou.hda.installFile(filepath)
        except Exception as e:
            print(e)
            return

        try:
            hda = hou.node("/obj").createNode(fx)
        except Exception as e:
            qd.error("Couldn't create node of type " + fx +
                     ". You should still be able to tab in the node manually.")

        try:
            hda.setName(fx, 1)
        except:
            pass

        try:
            hda.allowEditOfContents()
        except:
            pass

    def build_render(self):
        ris = hou.node("/out").createNode("cenote_layered_render")
        ris.parm("frame1").set(1)
        ris.parm("frame2").set(self.shotBody.get_frame_range())
        ris.parm("frame3").set(2)

        selected = None
        root = hou.node('/')
        camera_nodes = root.recursiveGlob('*', hou.nodeTypeFilter.ObjCamera)
        for cam in camera_nodes:
            if "shot" in cam.name():
                selected = cam
        if not selected:
            qd.error(
                "Error selecting camera for render. Will need to be done manually."
            )
        else:
            ris.parm("camera").set(selected.path())

        layers = self.build_layer_string()
        print(layers)
        ris.parm("render_layers").set(layers)

        ris.parm("build_rops").pressButton()

        for node in ris.children():
            if node.type().name() == "tractorsubmit_main":
                node.parm("job_title").set(self.shot_name + "_Test_Render")
            else:
                node.parm("override_camerares").set(True)
                old = node.parm("ri_display_0").unexpandedString()
                new = old.replace("render", "testRender")
                node.parm("ri_display_0").set(new)

    def build_layer_string(self):
        first = ""
        second = ""
        third = ""
        total = ""

        for node in hou.node("/obj").children():
            if node.type().name() == "cenoteAnimation":
                first = first + "[ " + node.name() + " ] "
            elif node.type().name() == "cenoteLayoutNet":
                third = third + node.name() + " "
            elif node.type().name(
            ) != "cenoteCamera" and not "sequence_lights" in node.name():
                second = second + node.name() + " "

        if len(first) > 0:
            total = total + first
        if len(second) > 0:
            total = total + "[ " + second + "] "
        if len(third) > 0:
            total = total + "[ " + third + "]"

        return total
class MaterialCloner:
    def __init__(self):
        self.project = Project()

    def clone(self):
        asset_list = self.project.list_existing_assets()

        self.item_gui = sfl.SelectFromList(
            l=asset_list,
            parent=hou.ui.mainQtWindow(),
            title="Select an asset's material to clone")
        self.item_gui.submitted.connect(self.results)

    def results(self, value):
        print("Selected asset: " + value[0])
        filename = value[0]

        self.body = Project().get_body(filename)
        self.element = self.body.get_element(Asset.MATERIALS)
        if self.element.get_last_version() >= 0:

            path = self.element.get_last_publish()[3]
            if path:
                createNewRef = True
                for child in hou.node("/stage").children():
                    if child.name(
                    ) == filename + "_material_ref" and child.parm(
                            "filepath1").eval() == path:
                        child.parm("reload").pressButton()
                        createNewRef = False
                if createNewRef:
                    ref = hou.node("/stage").createNode("reference")
                    ref.setName(filename + "_material_ref", 1)
                    ref.parm("filepath1").set(path)
                    ref.parm("primpath").set("/materials/")

                panes = self.getCurrentNetworkEditorPane()
                paths = []
                for pane in panes:
                    paths.append(pane.pwd())

                hdaPath = path.split(".")[0] + ".hda"
                hou.hda.installFile(hdaPath)

                success = False

                for p in paths:
                    try:
                        for child in p.children():
                            if child.type().name() == re.sub(
                                    r'\W+', '', filename):
                                child.destroy()
                        newMat = p.createNode(re.sub(r'\W+', '', filename))
                        newMat.setName(filename, 1)
                        newMat.setMaterialFlag(True)
                        success = True
                    except:
                        pass

                if not success:
                    for child in hou.node("/mat").children():
                        if child.type().name() == re.sub(r'\W+', '', filename):
                            child.destroy()
                    newMat = hou.node("/mat").createNode(
                        re.sub(r'\W+', '', filename))
                    newMat.setName(filename, 1)
                    newMat.setMaterialFlag(True)

                    qd.message(
                        "Material successfully cloned into /mat context.")

        else:
            qd.error("Nothing was cloned")

    def getCurrentNetworkEditorPane(self):
        editors = [
            pane for pane in hou.ui.paneTabs()
            if isinstance(pane, hou.NetworkEditor) and pane.isCurrentTab()
        ]
        return editors
Exemplo n.º 13
0
class AlembicExporter:
    def __init__(self, frame_range=1):
        self.frame_range = frame_range
        pm.loadPlugin("AbcExport")

    def asset_results(self, value):
        chosen_asset = value[0]
        print(chosen_asset)


    def exportSelected(self, asset_name, shot_name, camera=False):

        self.shot_name = shot_name
        self.shot = Project().get_shot(shot_name)

        if self.shot is None:
            return None

        start_frame = 0
        frame_range = str(self.shot.get_frame_range())
        #This means there's been no cameras even published for this shot but they're trying to save an animation. shouldn't ever happen
        if int(frame_range) == 0 and not camera:
            qd.error("How are you publishing without a camera yet? Get that done, bestie.")
            return
        #if this is previs we need to know where to move the keyframes to
        if camera:
            #ask the artist what frame the shot starts at and make sure that's a valid input
            start_frame = qd.input("Enter the starting frame for this shot")
            if start_frame is None or start_frame == u'':
                qd.error("Invalid frame range. Try publishing again.")
                return
            start_frame = str(start_frame)
            if not start_frame.isdigit():
                qd.error("Invalid frame range. Try publishing again.")
                return
            
            #ask the artist for the last frame and make sure that's valid input
            #we'll do this every time in case the length of the shot changes
            end_frame = qd.input("Enter the last frame for this shot")
            if end_frame is None or end_frame == u'':
                qd.error("Invalid frame range. Try publishing again.")
                return
            end_frame = str(end_frame)
            if not end_frame.isdigit():
                qd.error("Invalid frame range. Try publishing again.")
                return

            #calculate the frame-range and save it to the shot's .body file
            frame_range = int(end_frame) - int(start_frame) + 1
            self.shot.set_frame_range(frame_range)

            #now move the keyframes and build the command
            timeChange = int(start_frame) - 1
            anim_curves = mc.ls(type=['animCurveTA', 'animCurveTL', 'animCurveTT', 'animCurveTU'])  
            for each in anim_curves:  
                mc.keyframe(each, edit=True, relative=True, timeChange=-timeChange)

            path = self.getCameraPath(asset_name)
            command = self.buildAlembicCommand(path, uv=False)
                
        else:
            path = self.getFilePath(asset_name)
            command = self.buildAlembicCommand(path)
        

        cont = qd.yes_or_no("This asset is about to be saved with " + str(frame_range) + " frames. Is that correct?")
        if not cont:
            qd.error("Nothing was published.")
            return

        pm.Mel.eval(command)
        
        #now move the keyframes back for previs
        if camera:
            timeChange = int(start_frame) - 1
            anim_curves = mc.ls(type=['animCurveTA', 'animCurveTL', 'animCurveTT', 'animCurveTU'])  
            for each in anim_curves:  
                mc.keyframe(each, edit=True, relative=True, timeChange=timeChange)

        publish_info = [self.element, path]
        return publish_info

    def buildAlembicCommand(self, path, uv=True):
        #get selected nodes
        selected = mc.ls(sl=True,long=True)
        nodes = ""
        for node in selected:
            nodes += node
            nodes += " "

        frame_range = str(self.shot.get_frame_range())

        options = "-frameRange -48 " + frame_range
        if uv:
            options += " -uvWrite -writeUVSets"
        options += " -worldSpace -dataFormat ogawa -root " + nodes + "-file " + path

        command = "AbcExport -verbose -j \"" + options +"\""
        print(command)
        return command

    def getFilePath(self, asset_name):
        path = self.shot.get_filepath()
        dept = os.path.join(Asset.ANIMATION, asset_name) #this is to make it so we can keep track of the versions of animations for each asset
        path = os.path.join(path, dept)

        #try to create the element if it doesn't exist
        self.element = self.shot.create_element(dept, Element.DEFAULT_NAME)
        #retrieve it if it does already
        if self.element is None:
            self.element = self.shot.get_element(dept)
            
        self.element.update_app_ext(".abc")

        path = os.path.join(path, asset_name)
        last_version = self.element.get_last_version()
        current_version = last_version + 1
        path = path + "_v" + str(current_version).zfill(3) + ".abc"
        print(path)
        return path

    def getCameraPath(self, camera_name):
        path = self.shot.get_filepath()
        dept = os.path.join(Asset.CAMERA, camera_name) #this is to make it so we can keep track of the versions of animations for each camera
        path = os.path.join(path, dept)

        #try to create the element if it doesn't exist
        self.element = self.shot.create_element(dept, Element.DEFAULT_NAME)
        #retrieve it if it does already
        if self.element is None:
            self.element = self.shot.get_element(dept)

        self.element.update_app_ext(".abc")

        path = os.path.join(path, camera_name)
        last_version = self.element.get_last_version()
        current_version = last_version + 1
        path = path + "_v" + str(current_version).zfill(3) + ".abc"
        print(path)
        return path