Skip to content

load_hda

HdaLoader

Bases: HoudiniLoader

Load Houdini Digital Asset file.

Source code in client/ayon_houdini/plugins/load/load_hda.py
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
class HdaLoader(plugin.HoudiniLoader):
    """Load Houdini Digital Asset file."""

    product_types = {"hda"}
    label = "Load Hda"
    representations = {"hda"}
    order = -10
    icon = "code-fork"
    color = "orange"

    def load(self, context, name=None, namespace=None, data=None):

        # Format file name, Houdini only wants forward slashes
        file_path = self.filepath_from_context(context)
        file_path = os.path.normpath(file_path)
        file_path = file_path.replace("\\", "/")

        namespace = namespace or context["folder"]["name"]
        node_name = "{}_{}".format(namespace, name) if namespace else name

        hou.hda.installFile(file_path)

        hda_defs = hou.hda.definitionsInFile(file_path)
        if not hda_defs:
            raise LoadError(f"No HDA definitions found in file: {file_path}")

        parent_node = self._create_dedicated_parent_node(hda_defs[-1])

        # Get the type name from the HDA definition.
        type_name = hda_defs[-1].nodeTypeName()
        hda_node = parent_node.createNode(type_name, node_name)
        hda_node.moveToGoodPosition()

        # Imprint it manually
        data = {
            "schema": "openpype:container-2.0",
            "id": AVALON_CONTAINER_ID,
            "name": node_name,
            "namespace": namespace,
            "loader": self.__class__.__name__,
            "representation": context["representation"]["id"],
        }

        lib.imprint(hda_node, data)

        return hda_node

    def update(self, container, context):

        repre_entity = context["representation"]
        hda_node = container["node"]
        file_path = get_representation_path(repre_entity)
        file_path = file_path.replace("\\", "/")
        hou.hda.installFile(file_path)
        defs = hda_node.type().allInstalledDefinitions()
        def_paths = [d.libraryFilePath() for d in defs]
        new = def_paths.index(file_path)
        defs[new].setIsPreferred(True)
        hda_node.setParms({
            "representation": repre_entity["id"]
        })

        # Move the Extra parameter folder to the back.
        parm_group = hda_node.parmTemplateGroup()
        # The name 'Extra' is a hard coded name in AYON.
        parm_folder = parm_group.findFolder("Extra")
        # Remove `Extra` AYON parameters
        parm_group.remove(parm_folder.name())
        # Add `Extra` AYON parameters back
        parm_group.append(parm_folder)
        hda_node.setParmTemplateGroup(parm_group)

    def remove(self, container):
        node = container["node"]
        parent = node.parent()
        node.destroy()

        if parent.path() == pipeline.AVALON_CONTAINERS:
            return

        # Remove parent if empty.
        if not parent.children():
            parent.destroy()

    def _create_dedicated_parent_node(self, hda_def):

        # Get the root node
        parent_node = pipeline.get_or_create_avalon_container()
        node = None
        node_type = None
        if hda_def.nodeTypeCategory() == hou.objNodeTypeCategory():
            return parent_node
        elif hda_def.nodeTypeCategory() == hou.chopNodeTypeCategory():
            node_type, node_name = "chopnet", "MOTION"
        elif hda_def.nodeTypeCategory() == hou.cop2NodeTypeCategory():
            node_type, node_name = "cop2net", "IMAGES"
        elif hda_def.nodeTypeCategory() == hou.dopNodeTypeCategory():
            node_type, node_name = "dopnet", "DOPS"
        elif hda_def.nodeTypeCategory() == hou.ropNodeTypeCategory():
            node_type, node_name = "ropnet", "ROPS"
        elif hda_def.nodeTypeCategory() == hou.lopNodeTypeCategory():
            node_type, node_name = "lopnet", "LOPS"
        elif hda_def.nodeTypeCategory() == hou.sopNodeTypeCategory():
            node_type, node_name = "geo", "SOPS"
        elif hda_def.nodeTypeCategory() == hou.topNodeTypeCategory():
            node_type, node_name = "topnet", "TOPS"
        # TODO: Create a dedicated parent node based on Vop Node vex context.
        elif hda_def.nodeTypeCategory() == hou.vopNodeTypeCategory():
            node_type, node_name = "matnet", "MATSandVOPS"

        node = parent_node.node(node_name)
        if not node:
            node = parent_node.createNode(node_type, node_name)

        node.moveToGoodPosition()
        return node