Skip to content

Commit

Permalink
move houdini client code to its dedicated place and update imports
Browse files Browse the repository at this point in the history
  • Loading branch information
MustafaJafar committed May 14, 2024
1 parent 84a6041 commit 7c71563
Show file tree
Hide file tree
Showing 133 changed files with 13,093 additions and 1 deletion.
10 changes: 10 additions & 0 deletions client/ayon_houdini/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from .addon import (
HoudiniAddon,
HOUDINI_HOST_DIR,
)


__all__ = (
"HoudiniAddon",
"HOUDINI_HOST_DIR",
)
51 changes: 51 additions & 0 deletions client/ayon_houdini/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import os
from ayon_core.addon import AYONAddon, IHostAddon

HOUDINI_HOST_DIR = os.path.dirname(os.path.abspath(__file__))


class HoudiniAddon(AYONAddon, IHostAddon):
name = "houdini"
host_name = "houdini"

def add_implementation_envs(self, env, _app):
# Add requirements to HOUDINI_PATH and HOUDINI_MENU_PATH
startup_path = os.path.join(HOUDINI_HOST_DIR, "startup")
new_houdini_path = [startup_path]
new_houdini_menu_path = [startup_path]

old_houdini_path = env.get("HOUDINI_PATH") or ""
old_houdini_menu_path = env.get("HOUDINI_MENU_PATH") or ""

for path in old_houdini_path.split(os.pathsep):
if not path:
continue

norm_path = os.path.normpath(path)
if norm_path not in new_houdini_path:
new_houdini_path.append(norm_path)

for path in old_houdini_menu_path.split(os.pathsep):
if not path:
continue

norm_path = os.path.normpath(path)
if norm_path not in new_houdini_menu_path:
new_houdini_menu_path.append(norm_path)

# Add ampersand for unknown reason (Maybe is needed in Houdini?)
new_houdini_path.append("&")
new_houdini_menu_path.append("&")

env["HOUDINI_PATH"] = os.pathsep.join(new_houdini_path)
env["HOUDINI_MENU_PATH"] = os.pathsep.join(new_houdini_menu_path)

def get_launch_hook_paths(self, app):
if app.host_name != self.host_name:
return []
return [
os.path.join(HOUDINI_HOST_DIR, "hooks")
]

def get_workfile_extensions(self):
return [".hip", ".hiplc", ".hipnc"]
34 changes: 34 additions & 0 deletions client/ayon_houdini/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from .pipeline import (
HoudiniHost,
ls,
containerise
)

from .plugin import (
Creator,
)

from .lib import (
lsattr,
lsattrs,
read,

maintained_selection
)


__all__ = [
"HoudiniHost",

"ls",
"containerise",

"Creator",

# Utility functions
"lsattr",
"lsattrs",
"read",

"maintained_selection"
]
83 changes: 83 additions & 0 deletions client/ayon_houdini/api/action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import pyblish.api
import hou

from ayon_core.pipeline.publish import get_errored_instances_from_context


class SelectInvalidAction(pyblish.api.Action):
"""Select invalid nodes in Maya when plug-in failed.
To retrieve the invalid nodes this assumes a static `get_invalid()`
method is available on the plugin.
"""
label = "Select invalid"
on = "failed" # This action is only available on a failed plug-in
icon = "search" # Icon from Awesome Icon

def process(self, context, plugin):

errored_instances = get_errored_instances_from_context(context,
plugin=plugin)

# Get the invalid nodes for the plug-ins
self.log.info("Finding invalid nodes..")
invalid = list()
for instance in errored_instances:
invalid_nodes = plugin.get_invalid(instance)
if invalid_nodes:
if isinstance(invalid_nodes, (list, tuple)):
invalid.extend(invalid_nodes)
else:
self.log.warning("Plug-in returned to be invalid, "
"but has no selectable nodes.")

hou.clearAllSelected()
if invalid:
self.log.info("Selecting invalid nodes: {}".format(
", ".join(node.path() for node in invalid)
))
for node in invalid:
node.setSelected(True)
node.setCurrent(True)
else:
self.log.info("No invalid nodes found.")


class SelectROPAction(pyblish.api.Action):
"""Select ROP.
It's used to select the associated ROPs with the errored instances.
"""

label = "Select ROP"
on = "failed" # This action is only available on a failed plug-in
icon = "mdi.cursor-default-click"

def process(self, context, plugin):
errored_instances = get_errored_instances_from_context(context, plugin)

# Get the invalid nodes for the plug-ins
self.log.info("Finding ROP nodes..")
rop_nodes = list()
for instance in errored_instances:
node_path = instance.data.get("instance_node")
if not node_path:
continue

node = hou.node(node_path)
if not node:
continue

rop_nodes.append(node)

hou.clearAllSelected()
if rop_nodes:
self.log.info("Selecting ROP nodes: {}".format(
", ".join(node.path() for node in rop_nodes)
))
for node in rop_nodes:
node.setSelected(True)
node.setCurrent(True)
else:
self.log.info("No ROP nodes found.")
69 changes: 69 additions & 0 deletions client/ayon_houdini/api/colorspace.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import attr
import hou
from ayon_houdini.api.lib import get_color_management_preferences
from ayon_core.pipeline.colorspace import get_display_view_colorspace_name

@attr.s
class LayerMetadata(object):
"""Data class for Render Layer metadata."""
frameStart = attr.ib()
frameEnd = attr.ib()


@attr.s
class RenderProduct(object):
"""Getting Colorspace as
Specific Render Product Parameter for submitting
publish job.
"""
colorspace = attr.ib() # colorspace
view = attr.ib()
productName = attr.ib(default=None)


class ARenderProduct(object):

def __init__(self):
"""Constructor."""
# Initialize
self.layer_data = self._get_layer_data()
self.layer_data.products = self.get_colorspace_data()

def _get_layer_data(self):
return LayerMetadata(
frameStart=int(hou.playbar.frameRange()[0]),
frameEnd=int(hou.playbar.frameRange()[1]),
)

def get_colorspace_data(self):
"""To be implemented by renderer class.
This should return a list of RenderProducts.
Returns:
list: List of RenderProduct
"""
data = get_color_management_preferences()
colorspace_data = [
RenderProduct(
colorspace=data["display"],
view=data["view"],
productName=""
)
]
return colorspace_data


def get_default_display_view_colorspace():
"""Returns the colorspace attribute of the default (display, view) pair.
It's used for 'ociocolorspace' parm in OpenGL Node."""

prefs = get_color_management_preferences()
return get_display_view_colorspace_name(
config_path=prefs["config"],
display=prefs["display"],
view=prefs["view"]
)
Loading

0 comments on commit 7c71563

Please sign in to comment.