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
Exemple #2
0
    def getFilePath(self, name):
        asset = Project().get_asset(name)
        path = asset.get_filepath()
        path = os.path.join(path, Asset.GEO)

        self.element = Element(path)
        self.element.update_app_ext(".obj")

        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) + ".obj"
        # print(path)
        return path
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()
Exemple #4
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