mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge pull request #294 from BigRoy/enhancement/houdini_load_asset_lop
Houdini: Implement Load Asset LOP HDA
This commit is contained in:
commit
f87bd0871b
29 changed files with 1902 additions and 119 deletions
593
server_addon/houdini/client/ayon_houdini/api/hda_utils.py
Normal file
593
server_addon/houdini/client/ayon_houdini/api/hda_utils.py
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
"""Helper functions for load HDA"""
|
||||
|
||||
import os
|
||||
import contextlib
|
||||
import uuid
|
||||
from typing import List
|
||||
|
||||
import ayon_api
|
||||
from ayon_api import (
|
||||
get_project,
|
||||
get_representation_by_id,
|
||||
get_versions,
|
||||
get_folder_by_path,
|
||||
get_product_by_name,
|
||||
get_version_by_name,
|
||||
get_representation_by_name
|
||||
)
|
||||
from ayon_core.pipeline.load import (
|
||||
get_representation_context,
|
||||
get_representation_path_from_context
|
||||
)
|
||||
from ayon_core.pipeline.context_tools import (
|
||||
get_current_project_name,
|
||||
get_current_folder_path
|
||||
)
|
||||
from ayon_core.tools.utils import SimpleFoldersWidget
|
||||
from ayon_core.style import load_stylesheet
|
||||
|
||||
from ayon_houdini.api import lib
|
||||
|
||||
from qtpy import QtCore, QtWidgets
|
||||
import hou
|
||||
|
||||
|
||||
def is_valid_uuid(value) -> bool:
|
||||
"""Return whether value is a valid UUID"""
|
||||
try:
|
||||
uuid.UUID(value)
|
||||
except ValueError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def _unlocked_parm(parm):
|
||||
"""Unlock parm during context; will always lock after"""
|
||||
try:
|
||||
parm.lock(False)
|
||||
yield
|
||||
finally:
|
||||
parm.lock(True)
|
||||
|
||||
|
||||
def get_available_versions(node):
|
||||
"""Return the versions list for node.
|
||||
|
||||
The versions are sorted with the latest version first and oldest lower
|
||||
version last.
|
||||
|
||||
Args:
|
||||
node (hou.Node): Node to query selected products' versions for.
|
||||
|
||||
Returns:
|
||||
list[int]: Version numbers for the product
|
||||
"""
|
||||
|
||||
project_name = node.evalParm("project_name") or get_current_project_name()
|
||||
folder_path = node.evalParm("folder_path")
|
||||
product_name = node.evalParm("product_name")
|
||||
|
||||
if not all([
|
||||
project_name, folder_path, product_name
|
||||
]):
|
||||
return []
|
||||
|
||||
folder_entity = get_folder_by_path(
|
||||
project_name,
|
||||
folder_path,
|
||||
fields={"id"})
|
||||
if not folder_entity:
|
||||
return []
|
||||
product_entity = get_product_by_name(
|
||||
project_name,
|
||||
product_name=product_name,
|
||||
folder_id=folder_entity["id"],
|
||||
fields={"id"})
|
||||
if not product_entity:
|
||||
return []
|
||||
|
||||
# TODO: Support hero versions
|
||||
versions = get_versions(
|
||||
project_name,
|
||||
product_ids={product_entity["id"]},
|
||||
fields={"version"},
|
||||
hero=False)
|
||||
version_names = [version["version"] for version in versions]
|
||||
version_names.reverse()
|
||||
return version_names
|
||||
|
||||
|
||||
def update_info(node, context):
|
||||
"""Update project, folder, product, version, representation name parms.
|
||||
|
||||
Arguments:
|
||||
node (hou.Node): Node to update
|
||||
context (dict): Context of representation
|
||||
|
||||
"""
|
||||
# TODO: Avoid 'duplicate' taking over the expression if originally
|
||||
# it was $OS and by duplicating, e.g. the `folder` does not exist
|
||||
# anymore since it is now `hero1` instead of `hero`
|
||||
# TODO: Support hero versions
|
||||
version = str(context["version"]["version"])
|
||||
|
||||
# We only set the values if the value does not match the currently
|
||||
# evaluated result of the other parms, so that if the project name
|
||||
# value was dynamically set by the user with an expression or alike
|
||||
# then if it still matches the value of the current representation id
|
||||
# we preserve it. In essence, only update the value if the current
|
||||
# *evaluated* value of the parm differs.
|
||||
parms = {
|
||||
"project_name": context["project"]["name"],
|
||||
"folder_path": context["folder"]["path"],
|
||||
"product_name": context["product"]["name"],
|
||||
"version": version,
|
||||
"representation_name": context["representation"]["name"],
|
||||
}
|
||||
parms = {key: value for key, value in parms.items()
|
||||
if node.evalParm(key) != value}
|
||||
parms["load_message"] = "" # clear any warnings/errors
|
||||
|
||||
# Note that these never trigger any parm callbacks since we do not
|
||||
# trigger the `parm.pressButton` and programmatically setting values
|
||||
# in Houdini does not trigger callbacks automatically
|
||||
node.setParms(parms)
|
||||
|
||||
|
||||
def _get_thumbnail(project_name: str, version_id: str, thumbnail_dir: str):
|
||||
folder = hou.text.expandString(thumbnail_dir)
|
||||
path = os.path.join(folder, "{}_thumbnail.jpg".format(version_id))
|
||||
expanded_path = hou.text.expandString(path)
|
||||
if os.path.isfile(expanded_path):
|
||||
return path
|
||||
|
||||
# Try and create a thumbnail cache file
|
||||
data = ayon_api.get_thumbnail(project_name,
|
||||
entity_type="version",
|
||||
entity_id=version_id)
|
||||
if data:
|
||||
thumbnail_dir_expanded = hou.text.expandString(thumbnail_dir)
|
||||
os.makedirs(thumbnail_dir_expanded, exist_ok=True)
|
||||
with open(expanded_path, "wb") as f:
|
||||
f.write(data.content)
|
||||
return path
|
||||
|
||||
|
||||
def set_representation(node, representation_id: str):
|
||||
file_parm = node.parm("file")
|
||||
if not representation_id:
|
||||
# Clear filepath and thumbnail
|
||||
with _unlocked_parm(file_parm):
|
||||
file_parm.set("")
|
||||
set_node_thumbnail(node, None)
|
||||
return
|
||||
|
||||
project_name = (
|
||||
node.evalParm("project_name")
|
||||
or get_current_project_name()
|
||||
)
|
||||
|
||||
# Ignore invalid representation ids silently
|
||||
# TODO remove - added for backwards compatibility with OpenPype scenes
|
||||
if not is_valid_uuid(representation_id):
|
||||
return
|
||||
|
||||
repre_entity = get_representation_by_id(project_name, representation_id)
|
||||
if not repre_entity:
|
||||
return
|
||||
|
||||
context = get_representation_context(project_name, repre_entity)
|
||||
update_info(node, context)
|
||||
path = get_representation_path_from_context(context)
|
||||
# Load fails on UNC paths with backslashes and also
|
||||
# fails to resolve @sourcename var with backslashed
|
||||
# paths correctly. So we force forward slashes
|
||||
path = path.replace("\\", "/")
|
||||
with _unlocked_parm(file_parm):
|
||||
file_parm.set(path)
|
||||
|
||||
if node.evalParm("show_thumbnail"):
|
||||
# Update thumbnail
|
||||
# TODO: Cache thumbnail path as well
|
||||
version_id = repre_entity["versionId"]
|
||||
thumbnail_dir = node.evalParm("thumbnail_cache_dir")
|
||||
thumbnail_path = _get_thumbnail(
|
||||
project_name, version_id, thumbnail_dir
|
||||
)
|
||||
set_node_thumbnail(node, thumbnail_path)
|
||||
|
||||
|
||||
def set_node_thumbnail(node, thumbnail: str):
|
||||
"""Update node thumbnail to thumbnail"""
|
||||
if thumbnail is None:
|
||||
lib.set_node_thumbnail(node, None)
|
||||
|
||||
rect = compute_thumbnail_rect(node)
|
||||
lib.set_node_thumbnail(node, thumbnail, rect)
|
||||
|
||||
|
||||
def compute_thumbnail_rect(node):
|
||||
"""Compute thumbnail bounding rect based on thumbnail parms"""
|
||||
offset_x = node.evalParm("thumbnail_offsetx")
|
||||
offset_y = node.evalParm("thumbnail_offsety")
|
||||
width = node.evalParm("thumbnail_size")
|
||||
# todo: compute height from aspect of actual image file.
|
||||
aspect = 0.5625 # for now assume 16:9
|
||||
height = width * aspect
|
||||
|
||||
center = 0.5
|
||||
half_width = (width * .5)
|
||||
|
||||
return hou.BoundingRect(
|
||||
offset_x + center - half_width,
|
||||
offset_y,
|
||||
offset_x + center + half_width,
|
||||
offset_y + height
|
||||
)
|
||||
|
||||
|
||||
def on_thumbnail_show_changed(node):
|
||||
"""Callback on thumbnail show parm changed"""
|
||||
if node.evalParm("show_thumbnail"):
|
||||
# For now, update all
|
||||
on_representation_id_changed(node)
|
||||
else:
|
||||
lib.remove_all_thumbnails(node)
|
||||
|
||||
|
||||
def on_thumbnail_size_changed(node):
|
||||
"""Callback on thumbnail offset or size parms changed"""
|
||||
thumbnail = lib.get_node_thumbnail(node)
|
||||
if thumbnail:
|
||||
rect = compute_thumbnail_rect(node)
|
||||
thumbnail.setRect(rect)
|
||||
lib.set_node_thumbnail(node, thumbnail)
|
||||
|
||||
|
||||
def on_representation_id_changed(node):
|
||||
"""Callback on representation id changed
|
||||
|
||||
Args:
|
||||
node (hou.Node): Node to update.
|
||||
"""
|
||||
repre_id = node.evalParm("representation")
|
||||
set_representation(node, repre_id)
|
||||
|
||||
|
||||
def on_representation_parms_changed(node):
|
||||
"""
|
||||
Usually used as callback to the project, folder, product, version and
|
||||
representation parms which on change - would result in a different
|
||||
representation id to be resolved.
|
||||
|
||||
Args:
|
||||
node (hou.Node): Node to update.
|
||||
"""
|
||||
project_name = node.evalParm("project_name") or get_current_project_name()
|
||||
representation_id = get_representation_id(
|
||||
project_name=project_name,
|
||||
folder_path=node.evalParm("folder_path"),
|
||||
product_name=node.evalParm("product_name"),
|
||||
version=node.evalParm("version"),
|
||||
representation_name=node.evalParm("representation_name"),
|
||||
load_message_parm=node.parm("load_message")
|
||||
)
|
||||
if representation_id is None:
|
||||
representation_id = ""
|
||||
else:
|
||||
representation_id = str(representation_id)
|
||||
|
||||
if node.evalParm("representation") != representation_id:
|
||||
node.parm("representation").set(representation_id)
|
||||
node.parm("representation").pressButton() # trigger callback
|
||||
|
||||
|
||||
def get_representation_id(
|
||||
project_name,
|
||||
folder_path,
|
||||
product_name,
|
||||
version,
|
||||
representation_name,
|
||||
load_message_parm,
|
||||
):
|
||||
"""Get representation id.
|
||||
|
||||
Args:
|
||||
project_name (str): Project name
|
||||
folder_path (str): Folder name
|
||||
product_name (str): Product name
|
||||
version (str): Version name as string
|
||||
representation_name (str): Representation name
|
||||
load_message_parm (hou.Parm): A string message parm to report
|
||||
any error messages to.
|
||||
|
||||
Returns:
|
||||
Optional[str]: Representation id or None if not found.
|
||||
|
||||
"""
|
||||
|
||||
if not all([
|
||||
project_name, folder_path, product_name, version, representation_name
|
||||
]):
|
||||
labels = {
|
||||
"project": project_name,
|
||||
"folder": folder_path,
|
||||
"product": product_name,
|
||||
"version": version,
|
||||
"representation": representation_name
|
||||
}
|
||||
missing = ", ".join(key for key, value in labels.items() if not value)
|
||||
load_message_parm.set(f"Load info incomplete. Found empty: {missing}")
|
||||
return
|
||||
|
||||
try:
|
||||
version = int(version.strip())
|
||||
except ValueError:
|
||||
load_message_parm.set(f"Invalid version format: '{version}'\n"
|
||||
"Make sure to set a valid version number.")
|
||||
return
|
||||
|
||||
folder_entity = get_folder_by_path(project_name,
|
||||
folder_path=folder_path,
|
||||
fields={"id"})
|
||||
if not folder_entity:
|
||||
# This may be due to the project not existing - so let's validate
|
||||
# that first
|
||||
if not get_project(project_name):
|
||||
load_message_parm.set(f"Project not found: '{project_name}'")
|
||||
return
|
||||
load_message_parm.set(f"Folder not found: '{folder_path}'")
|
||||
return
|
||||
|
||||
product_entity = get_product_by_name(
|
||||
project_name,
|
||||
product_name=product_name,
|
||||
folder_id=folder_entity["id"],
|
||||
fields={"id"})
|
||||
if not product_entity:
|
||||
load_message_parm.set(f"Product not found: '{product_name}'")
|
||||
return
|
||||
version_entity = get_version_by_name(
|
||||
project_name,
|
||||
version,
|
||||
product_id=product_entity["id"],
|
||||
fields={"id"})
|
||||
if not version_entity:
|
||||
load_message_parm.set(f"Version not found: '{version}'")
|
||||
return
|
||||
representation_entity = get_representation_by_name(
|
||||
project_name,
|
||||
representation_name,
|
||||
version_id=version_entity["id"],
|
||||
fields={"id"})
|
||||
if not representation_entity:
|
||||
load_message_parm.set(
|
||||
f"Representation not found: '{representation_name}'.")
|
||||
return
|
||||
return representation_entity["id"]
|
||||
|
||||
|
||||
def setup_flag_changed_callback(node):
|
||||
"""Register flag changed callback (for thumbnail brightness)"""
|
||||
node.addEventCallback(
|
||||
(hou.nodeEventType.FlagChanged,),
|
||||
on_flag_changed
|
||||
)
|
||||
|
||||
|
||||
def on_flag_changed(node, **kwargs):
|
||||
"""On node flag changed callback.
|
||||
|
||||
Updates the brightness of attached thumbnails
|
||||
"""
|
||||
# Showing thumbnail is disabled so can return early since
|
||||
# there should be no thumbnail to update.
|
||||
if not node.evalParm('show_thumbnail'):
|
||||
return
|
||||
|
||||
# Update node thumbnails brightness with the
|
||||
# bypass state of the node.
|
||||
parent = node.parent()
|
||||
images = lib.get_background_images(parent)
|
||||
if not images:
|
||||
return
|
||||
|
||||
brightness = 0.3 if node.isBypassed() else 1.0
|
||||
has_changes = False
|
||||
node_path = node.path()
|
||||
for image in images:
|
||||
if image.relativeToPath() == node_path:
|
||||
image.setBrightness(brightness)
|
||||
has_changes = True
|
||||
|
||||
if has_changes:
|
||||
lib.set_background_images(parent, images)
|
||||
|
||||
|
||||
def keep_background_images_linked(node, old_name):
|
||||
"""Reconnect background images to node from old name.
|
||||
|
||||
Used as callback on node name changes to keep thumbnails linked."""
|
||||
from ayon_houdini.api.lib import (
|
||||
get_background_images,
|
||||
set_background_images
|
||||
)
|
||||
|
||||
parent = node.parent()
|
||||
images = get_background_images(parent)
|
||||
if not images:
|
||||
return
|
||||
|
||||
changes = False
|
||||
old_path = f"{node.parent().path()}/{old_name}"
|
||||
for image in images:
|
||||
if image.relativeToPath() == old_path:
|
||||
image.setRelativeToPath(node.path())
|
||||
changes = True
|
||||
|
||||
if changes:
|
||||
set_background_images(parent, images)
|
||||
|
||||
|
||||
class SelectFolderPathDialog(QtWidgets.QDialog):
|
||||
"""Simple dialog to allow a user to select project and asset."""
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(SelectFolderPathDialog, self).__init__(parent)
|
||||
self.setWindowTitle("Set project and folder path")
|
||||
self.setStyleSheet(load_stylesheet())
|
||||
|
||||
project_widget = QtWidgets.QComboBox()
|
||||
project_widget.addItems(self.get_projects())
|
||||
|
||||
filter_widget = QtWidgets.QLineEdit()
|
||||
filter_widget.setPlaceholderText("Folder name filter...")
|
||||
|
||||
folder_widget = SimpleFoldersWidget(parent=self)
|
||||
|
||||
accept_button = QtWidgets.QPushButton("Accept")
|
||||
|
||||
main_layout = QtWidgets.QVBoxLayout(self)
|
||||
main_layout.addWidget(project_widget, 0)
|
||||
main_layout.addWidget(filter_widget, 0)
|
||||
main_layout.addWidget(folder_widget, 1)
|
||||
main_layout.addWidget(accept_button, 0)
|
||||
|
||||
self.project_widget = project_widget
|
||||
self.folder_widget = folder_widget
|
||||
|
||||
project_widget.currentTextChanged.connect(self.on_project_changed)
|
||||
filter_widget.textChanged.connect(folder_widget.set_name_filter)
|
||||
folder_widget.double_clicked.connect(self.accept)
|
||||
accept_button.clicked.connect(self.accept)
|
||||
|
||||
def get_selected_folder_path(self) -> str:
|
||||
return self.folder_widget.get_selected_folder_path()
|
||||
|
||||
def get_selected_project_name(self) -> str:
|
||||
return self.project_widget.currentText()
|
||||
|
||||
def get_projects(self) -> List[str]:
|
||||
projects = ayon_api.get_projects(fields=["name"])
|
||||
return [p["name"] for p in projects]
|
||||
|
||||
def on_project_changed(self, project_name: str):
|
||||
self.folder_widget.set_project_name(project_name)
|
||||
|
||||
def set_project_name(self, project_name: str):
|
||||
self.project_widget.setCurrentText(project_name)
|
||||
|
||||
if self.project_widget.currentText() != project_name:
|
||||
# Project does not exist
|
||||
return
|
||||
|
||||
# Force the set of widget because even though a callback exist on the
|
||||
# project widget it may have been initialized to that value and hence
|
||||
# detect no change.
|
||||
self.folder_widget.set_project_name(project_name)
|
||||
|
||||
|
||||
def select_folder_path(node):
|
||||
"""Show dialog to select folder path.
|
||||
|
||||
When triggered it opens a dialog that shows the available
|
||||
folder paths within a given project.
|
||||
|
||||
Note:
|
||||
This function should be refactored.
|
||||
It currently shows the available
|
||||
folder paths within the current project only.
|
||||
|
||||
Args:
|
||||
node (hou.OpNode): The HDA node.
|
||||
"""
|
||||
main_window = lib.get_main_window()
|
||||
|
||||
project_name = node.evalParm("project_name")
|
||||
folder_path = node.evalParm("folder_path")
|
||||
|
||||
dialog = SelectFolderPathDialog(parent=main_window)
|
||||
dialog.set_project_name(project_name)
|
||||
if folder_path:
|
||||
# We add a small delay to the setting of the selected folder
|
||||
# because the folder widget's set project logic itself also runs
|
||||
# with a bit of a delay, and unfortunately otherwise the project
|
||||
# has not been selected yet and thus selection does not work.
|
||||
def _select_folder_path():
|
||||
dialog.folder_widget.set_selected_folder_path(folder_path)
|
||||
QtCore.QTimer.singleShot(100, _select_folder_path)
|
||||
|
||||
dialog.setStyleSheet(load_stylesheet())
|
||||
|
||||
result = dialog.exec_()
|
||||
if result != QtWidgets.QDialog.Accepted:
|
||||
return
|
||||
|
||||
# Set project
|
||||
selected_project_name = dialog.get_selected_project_name()
|
||||
if selected_project_name == get_current_project_name():
|
||||
selected_project_name = '$AYON_PROJECT_NAME'
|
||||
|
||||
project_parm = node.parm("project_name")
|
||||
project_parm.set(selected_project_name)
|
||||
project_parm.pressButton() # allow any callbacks to trigger
|
||||
|
||||
# Set folder path
|
||||
selected_folder_path = dialog.get_selected_folder_path()
|
||||
if not selected_folder_path:
|
||||
# Do nothing if user accepted with nothing selected
|
||||
return
|
||||
|
||||
if selected_folder_path == get_current_folder_path():
|
||||
selected_folder_path = '$AYON_FOLDER_PATH'
|
||||
|
||||
folder_parm = node.parm("folder_path")
|
||||
folder_parm.set(selected_folder_path)
|
||||
folder_parm.pressButton() # allow any callbacks to trigger
|
||||
|
||||
|
||||
def get_available_products(node):
|
||||
"""Return products menu items
|
||||
It gets a list of available products of the specified product types
|
||||
within the specified folder path with in the specified project.
|
||||
Users can specify those in the HDA parameters.
|
||||
|
||||
Args:
|
||||
node (hou.OpNode): The HDA node.
|
||||
|
||||
Returns:
|
||||
list[str]: Product names for Products menu.
|
||||
"""
|
||||
project_name = node.evalParm("project_name")
|
||||
folder_path = node.evalParm("folder_path")
|
||||
product_type = node.evalParm("product_type")
|
||||
|
||||
folder_entity = ayon_api.get_folder_by_path(project_name,
|
||||
folder_path,
|
||||
fields={"id"})
|
||||
if not folder_entity:
|
||||
return []
|
||||
|
||||
products = ayon_api.get_products(
|
||||
project_name,
|
||||
folder_ids=[folder_entity["id"]],
|
||||
product_types=[product_type]
|
||||
)
|
||||
|
||||
return [product["name"] for product in products]
|
||||
|
||||
|
||||
def set_to_latest_version(node):
|
||||
"""Callback on product name change
|
||||
|
||||
Refresh version parameter value by setting its value to
|
||||
the latest version of the selected product.
|
||||
|
||||
Args:
|
||||
node (hou.OpNode): The HDA node.
|
||||
"""
|
||||
|
||||
versions = get_available_versions(node)
|
||||
if versions:
|
||||
node.parm("version").set(str(versions[0]))
|
||||
|
|
@ -1037,6 +1037,231 @@ def sceneview_snapshot(
|
|||
log.debug("A snapshot of sceneview has been saved to: {}".format(filepath))
|
||||
|
||||
|
||||
def get_background_images(node, raw=False):
|
||||
""""Return background images defined inside node.
|
||||
|
||||
Similar to `nodegraphutils.saveBackgroundImages` but this method also
|
||||
allows to retrieve the data as JSON encodable data instead of
|
||||
`hou.NetworkImage` instances when using `raw=True`
|
||||
"""
|
||||
|
||||
def _parse(image_data):
|
||||
image = hou.NetworkImage(image_data["path"],
|
||||
hou.BoundingRect(*image_data["rect"]))
|
||||
if "relativetopath" in image_data:
|
||||
image.setRelativeToPath(image_data["relativetopath"])
|
||||
if "brightness" in image_data:
|
||||
image.setBrightness(image_data["brightness"])
|
||||
return image
|
||||
|
||||
data = node.userData("backgroundimages")
|
||||
if not data:
|
||||
return []
|
||||
|
||||
try:
|
||||
images = json.loads(data)
|
||||
except json.decoder.JSONDecodeError:
|
||||
images = []
|
||||
|
||||
if not raw:
|
||||
images = [_parse(_data) for _data in images]
|
||||
return images
|
||||
|
||||
|
||||
def set_background_images(node, images):
|
||||
"""Set hou.NetworkImage background images under given hou.Node
|
||||
|
||||
Similar to: `nodegraphutils.loadBackgroundImages`
|
||||
|
||||
"""
|
||||
|
||||
def _serialize(image):
|
||||
"""Return hou.NetworkImage as serialized dict"""
|
||||
if isinstance(image, dict):
|
||||
# Assume already serialized, only do some minor validations
|
||||
if "path" not in image:
|
||||
raise ValueError("Missing `path` key in image dictionary.")
|
||||
if "rect" not in image:
|
||||
raise ValueError("Missing `rect` key in image dictionary.")
|
||||
if len(image["rect"]) != 4:
|
||||
raise ValueError("`rect` value must be list of four floats.")
|
||||
return image
|
||||
|
||||
rect = image.rect()
|
||||
rect_min = rect.min()
|
||||
rect_max = rect.max()
|
||||
data = {
|
||||
"path": image.path(),
|
||||
"rect": [rect_min.x(), rect_min.y(), rect_max.x(), rect_max.y()],
|
||||
}
|
||||
if image.brightness() != 1.0:
|
||||
data["brightness"] = image.brightness()
|
||||
if image.relativeToPath():
|
||||
data["relativetopath"] = image.relativeToPath()
|
||||
return data
|
||||
|
||||
with hou.undos.group('Edit Background Images'):
|
||||
if images:
|
||||
assert all(isinstance(image, (dict, hou.NetworkImage))
|
||||
for image in images)
|
||||
data = json.dumps([_serialize(image) for image in images])
|
||||
node.setUserData("backgroundimages", data)
|
||||
else:
|
||||
node.destroyUserData("backgroundimages", must_exist=False)
|
||||
|
||||
|
||||
def set_node_thumbnail(node, image_path, rect=None):
|
||||
"""Set hou.NetworkImage attached to node.
|
||||
|
||||
If an existing connected image is found it assumes that is the existing
|
||||
thumbnail and will update that particular instance instead.
|
||||
|
||||
When `image_path` is None an existing attached `hou.NetworkImage` will be
|
||||
removed.
|
||||
|
||||
Arguments:
|
||||
node (hou.Node): Node to set thumbnail for.
|
||||
image_path (Union[str, None]): Path to image to set.
|
||||
If None is set then the thumbnail will be removed if it exists.
|
||||
rect (hou.BoundingRect): Bounding rect for the relative placement
|
||||
to the node.
|
||||
|
||||
Returns:
|
||||
hou.NetworkImage or None: The network image that was set or None if
|
||||
instead it not set or removed.
|
||||
|
||||
"""
|
||||
|
||||
parent = node.parent()
|
||||
images = get_background_images(parent)
|
||||
|
||||
node_path = node.path()
|
||||
# Find first existing image attached to node
|
||||
index, image = next(
|
||||
(
|
||||
(index, image) for index, image in enumerate(images) if
|
||||
image.relativeToPath() == node_path
|
||||
),
|
||||
(None, None)
|
||||
)
|
||||
if image_path is None:
|
||||
# Remove image if it exists
|
||||
if image:
|
||||
images.remove(image)
|
||||
set_background_images(parent, images)
|
||||
return
|
||||
|
||||
if rect is None:
|
||||
rect = hou.BoundingRect(-1, -1, 1, 1)
|
||||
|
||||
if isinstance(image_path, hou.NetworkImage):
|
||||
image = image_path
|
||||
if index is not None:
|
||||
images[index] = image
|
||||
else:
|
||||
images.append(image)
|
||||
elif image is None:
|
||||
# Create the image
|
||||
image = hou.NetworkImage(image_path, rect)
|
||||
image.setRelativeToPath(node.path())
|
||||
images.append(image)
|
||||
else:
|
||||
# Update first existing image
|
||||
image.setRect(rect)
|
||||
image.setPath(image_path)
|
||||
|
||||
set_background_images(parent, images)
|
||||
|
||||
return image
|
||||
|
||||
|
||||
def remove_all_thumbnails(node):
|
||||
"""Remove all node thumbnails.
|
||||
|
||||
Removes all network background images that are linked to the given node.
|
||||
"""
|
||||
parent = node.parent()
|
||||
images = get_background_images(parent)
|
||||
node_path = node.path()
|
||||
images = [
|
||||
image for image in images if image.relativeToPath() != node_path
|
||||
]
|
||||
set_background_images(parent, images)
|
||||
|
||||
|
||||
def get_node_thumbnail(node, first_only=True):
|
||||
"""Return node thumbnails.
|
||||
|
||||
Return network background images that are linked to the given node.
|
||||
By default, only returns the first one found, unless `first_only` is False.
|
||||
|
||||
Returns:
|
||||
Union[hou.NetworkImage, List[hou.NetworkImage]]:
|
||||
Connected network images
|
||||
|
||||
"""
|
||||
parent = node.parent()
|
||||
images = get_background_images(parent)
|
||||
node_path = node.path()
|
||||
|
||||
def is_attached_to_node(image):
|
||||
return image.relativeToPath() == node_path
|
||||
|
||||
attached_images = filter(is_attached_to_node, images)
|
||||
|
||||
# Find first existing image attached to node
|
||||
if first_only:
|
||||
return next(attached_images, None)
|
||||
else:
|
||||
return attached_images
|
||||
|
||||
|
||||
def find_active_network(category, default):
|
||||
"""Find the first active network editor in the UI.
|
||||
|
||||
If no active network editor pane is found at the given category then the
|
||||
`default` path will be used as fallback.
|
||||
|
||||
For example, to find an active LOPs network:
|
||||
>>> network = find_active_network(
|
||||
... category=hou.lopNodeTypeCategory(),
|
||||
... fallback="/stage"
|
||||
... )
|
||||
hou.Node("/stage/lopnet1")
|
||||
|
||||
Arguments:
|
||||
category (hou.NodeTypeCategory): The node network category type.
|
||||
default (str): The default path to fallback to if no active pane
|
||||
is found with the given category.
|
||||
|
||||
Returns:
|
||||
hou.Node: The node network to return.
|
||||
|
||||
"""
|
||||
# Find network editors that are current tab of given category
|
||||
index = 0
|
||||
while True:
|
||||
pane = hou.ui.paneTabOfType(hou.paneTabType.NetworkEditor, index)
|
||||
if pane is None:
|
||||
break
|
||||
|
||||
index += 1
|
||||
if not pane.isCurrentTab():
|
||||
continue
|
||||
|
||||
pwd = pane.pwd()
|
||||
if pwd.type().category() != category:
|
||||
continue
|
||||
|
||||
if not pwd.isEditable():
|
||||
continue
|
||||
|
||||
return pwd
|
||||
|
||||
# Default to the fallback if no valid candidate was found
|
||||
return hou.node(default)
|
||||
|
||||
|
||||
def update_content_on_context_change():
|
||||
"""Update all Creator instances to current asset"""
|
||||
host = registered_host()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Pipeline tools for OpenPype Houdini integration."""
|
||||
import os
|
||||
import json
|
||||
import logging
|
||||
|
||||
import hou # noqa
|
||||
|
|
@ -26,6 +27,8 @@ from ayon_core.lib import (
|
|||
env_value_to_bool,
|
||||
)
|
||||
|
||||
from .lib import JSON_PREFIX
|
||||
|
||||
|
||||
log = logging.getLogger("ayon_houdini")
|
||||
|
||||
|
|
@ -258,7 +261,25 @@ def parse_container(container):
|
|||
dict: The container schema data for this container node.
|
||||
|
||||
"""
|
||||
data = lib.read(container)
|
||||
# Read only relevant parms
|
||||
# TODO: Clean up this hack replacing `lib.read(container)`
|
||||
|
||||
data = {}
|
||||
for name in ["name", "namespace", "loader", "representation", "id"]:
|
||||
parm = container.parm(name)
|
||||
if not parm:
|
||||
return {}
|
||||
|
||||
value = parm.eval()
|
||||
|
||||
# test if value is json encoded dict
|
||||
if isinstance(value, str) and value.startswith(JSON_PREFIX):
|
||||
try:
|
||||
value = json.loads(value[len(JSON_PREFIX):])
|
||||
except json.JSONDecodeError:
|
||||
# not a json
|
||||
pass
|
||||
data[name] = value
|
||||
|
||||
# Backwards compatibility pre-schemas for containers
|
||||
data["schema"] = data.get("schema", "openpype:container-1.0")
|
||||
|
|
|
|||
|
|
@ -3,130 +3,12 @@
|
|||
import contextlib
|
||||
import logging
|
||||
|
||||
import ayon_api
|
||||
from qtpy import QtWidgets, QtCore, QtGui
|
||||
|
||||
from ayon_core import style
|
||||
from ayon_core.pipeline import get_current_project_name
|
||||
from ayon_core.tools.utils import (
|
||||
PlaceholderLineEdit,
|
||||
RefreshButton,
|
||||
SimpleFoldersWidget,
|
||||
)
|
||||
|
||||
from pxr import Sdf
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SelectFolderDialog(QtWidgets.QWidget):
|
||||
"""Frameless folders dialog to select folder with double click.
|
||||
|
||||
Args:
|
||||
parm: Parameter where selected folder path is set.
|
||||
"""
|
||||
|
||||
def __init__(self, parm):
|
||||
self.setWindowTitle("Pick Folder")
|
||||
self.setWindowFlags(QtCore.Qt.FramelessWindowHint | QtCore.Qt.Popup)
|
||||
|
||||
header_widget = QtWidgets.QWidget(self)
|
||||
|
||||
filter_input = PlaceholderLineEdit(header_widget)
|
||||
filter_input.setPlaceholderText("Filter folders..")
|
||||
|
||||
refresh_btn = RefreshButton(self)
|
||||
|
||||
header_layout = QtWidgets.QHBoxLayout(header_widget)
|
||||
header_layout.setContentsMargins(0, 0, 0, 0)
|
||||
header_layout.addWidget(filter_input)
|
||||
header_layout.addWidget(refresh_btn)
|
||||
|
||||
for widget in (
|
||||
refresh_btn,
|
||||
filter_input,
|
||||
):
|
||||
size_policy = widget.sizePolicy()
|
||||
size_policy.setVerticalPolicy(
|
||||
QtWidgets.QSizePolicy.MinimumExpanding)
|
||||
widget.setSizePolicy(size_policy)
|
||||
|
||||
folders_widget = SimpleFoldersWidget(self)
|
||||
folders_widget.set_project_name(get_current_project_name())
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.addWidget(header_widget, 0)
|
||||
layout.addWidget(folders_widget, 1)
|
||||
|
||||
folders_widget.double_clicked.connect(self._set_parameter)
|
||||
filter_input.textChanged.connect(self._on_filter_change)
|
||||
refresh_btn.clicked.connect(self._on_refresh_clicked)
|
||||
|
||||
self._folders_widget = folders_widget
|
||||
self._parm = parm
|
||||
|
||||
def _on_refresh_clicked(self):
|
||||
self._folders_widget.refresh()
|
||||
|
||||
def _on_filter_change(self, text):
|
||||
self._folders_widget.set_name_filter(text)
|
||||
|
||||
def _set_parameter(self):
|
||||
folder_path = self._folders_widget.get_selected_folder_path()
|
||||
self._parm.set(folder_path)
|
||||
self.close()
|
||||
|
||||
def _on_show(self):
|
||||
pos = QtGui.QCursor.pos()
|
||||
# Select the current folder if there is any
|
||||
select_id = None
|
||||
folder_path = self._parm.eval()
|
||||
if folder_path:
|
||||
project_name = get_current_project_name()
|
||||
folder_entity = ayon_api.get_folder_by_path(
|
||||
project_name, folder_path, fields={"id"}
|
||||
)
|
||||
if folder_entity:
|
||||
select_id = folder_entity["id"]
|
||||
|
||||
# Set stylesheet
|
||||
self.setStyleSheet(style.load_stylesheet())
|
||||
# Refresh folders (is threaded)
|
||||
self._folders_widget.refresh()
|
||||
# Select folder - must be done after refresh
|
||||
if select_id is not None:
|
||||
self._folders_widget.set_selected_folder(select_id)
|
||||
|
||||
# Show cursor (top right of window) near cursor
|
||||
self.resize(250, 400)
|
||||
self.move(self.mapFromGlobal(pos) - QtCore.QPoint(self.width(), 0))
|
||||
|
||||
def showEvent(self, event):
|
||||
super(SelectFolderDialog, self).showEvent(event)
|
||||
self._on_show()
|
||||
|
||||
|
||||
def pick_folder(node):
|
||||
"""Show a user interface to select an Folder in the project
|
||||
|
||||
When double clicking an folder it will set the Folder value in the
|
||||
'folderPath' parameter.
|
||||
|
||||
"""
|
||||
|
||||
parm = node.parm("folderPath")
|
||||
if not parm:
|
||||
log.error("Node has no 'folderPath' parameter: %s", node)
|
||||
return
|
||||
|
||||
# Construct a frameless popup so it automatically
|
||||
# closes when clicked outside of it.
|
||||
global tool
|
||||
tool = SelectFolderDialog(parm)
|
||||
tool.show()
|
||||
|
||||
|
||||
def add_usd_output_processor(ropnode, processor):
|
||||
"""Add USD Output Processor to USD Rop node.
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
from ayon_core.pipeline import load
|
||||
from ayon_houdini.api.lib import find_active_network
|
||||
|
||||
import hou
|
||||
|
||||
|
||||
class LOPLoadAssetLoader(load.LoaderPlugin):
|
||||
"""Load reference/payload into Solaris using AYON `lop_import` LOP"""
|
||||
|
||||
product_types = {"*"}
|
||||
label = "Load Asset (LOPs)"
|
||||
representations = ["usd", "abc", "usda", "usdc"]
|
||||
order = -10
|
||||
icon = "code-fork"
|
||||
color = "orange"
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
|
||||
# Define node name
|
||||
namespace = namespace if namespace else context["folder"]["name"]
|
||||
node_name = "{}_{}".format(namespace, name) if namespace else name
|
||||
|
||||
# Create node
|
||||
network = find_active_network(
|
||||
category=hou.lopNodeTypeCategory(),
|
||||
default="/stage"
|
||||
)
|
||||
node = network.createNode("ayon::lop_import", node_name=node_name)
|
||||
node.moveToGoodPosition()
|
||||
|
||||
# Set representation id
|
||||
parm = node.parm("representation")
|
||||
parm.set(context["representation"]["id"])
|
||||
parm.pressButton() # trigger callbacks
|
||||
|
||||
nodes = [node]
|
||||
self[:] = nodes
|
||||
|
||||
def update(self, container, context):
|
||||
node = container["node"]
|
||||
|
||||
# Set representation id
|
||||
parm = node.parm("representation")
|
||||
parm.set(context["representation"]["id"])
|
||||
parm.pressButton() # trigger callbacks
|
||||
|
||||
def remove(self, container):
|
||||
node = container["node"]
|
||||
node.destroy()
|
||||
|
||||
def switch(self, container, context):
|
||||
self.update(container, context)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Operator: ayon::lop_import::1.0
|
||||
Label: AYON Load Asset
|
||||
Path: oplib:/ayon::Lop/lop_import::1.0?ayon::Lop/lop_import::1.0
|
||||
Icon: opdef:/ayon::Lop/lop_import::1.0?IconImage
|
||||
Table: Lop
|
||||
License:
|
||||
Extra:
|
||||
User:
|
||||
Inputs: 0 to 1
|
||||
Subnet: true
|
||||
Python: false
|
||||
Empty: false
|
||||
Modified: Thu Jun 10 16:44:00 2024
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
""
|
||||
INDEX__SECTION INDEX_SECTION
|
||||
houdini.hdalibrary houdini.hdalibrary
|
||||
ayon_8_8Lop_1lop__import_8_81.0 ayon::Lop/lop_import::1.0
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"hdaroot/warn_no_representation_set.def":1708980551,
|
||||
"hdaroot/reference.def":1698150558,
|
||||
"hdaroot/output0.def":1698215383,
|
||||
"hdaroot.def":1717451587
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"values":["20.0.703"
|
||||
],
|
||||
"indexes":{
|
||||
"hdaroot/warn_no_representation_set.userdata":0,
|
||||
"hdaroot/reference.userdata":0,
|
||||
"hdaroot/output0.userdata":0
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY"
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="node_type"
|
||||
Content-Type: text/plain
|
||||
|
||||
Lop
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.init"
|
||||
Content-Type: text/plain
|
||||
|
||||
type = ayon::lop_import::1.0
|
||||
matchesdef = 0
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.def"
|
||||
Content-Type: text/plain
|
||||
|
||||
comment ""
|
||||
position -1.67827 1.26636
|
||||
connectornextid 0
|
||||
flags = lock off model off template off footprint off xray off bypass off display on render on highlight off unload off savedata off compress on colordefault on exposed on debug off
|
||||
outputsNamed3
|
||||
{
|
||||
}
|
||||
inputsNamed3
|
||||
{
|
||||
}
|
||||
inputs
|
||||
{
|
||||
}
|
||||
stat
|
||||
{
|
||||
create -1
|
||||
modify -1
|
||||
author Mustafa_Taher@Major-Kalawy
|
||||
access 0777
|
||||
}
|
||||
color UT_Color RGB 0.8 0.8 0.8
|
||||
delscript ""
|
||||
exprlanguage hscript
|
||||
end
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.userdata"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
"___Version___":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
},
|
||||
"wirestyle":{
|
||||
"type":"string",
|
||||
"value":"rounded"
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.inp"
|
||||
Content-Type: text/plain
|
||||
|
||||
1
|
||||
0 -1.3044269152357999 6.2635205889365251 2 0 __NO_OWNER_NETWORK_BOX__ "FROMOUTPUT"
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/output0.init"
|
||||
Content-Type: text/plain
|
||||
|
||||
type = output
|
||||
matchesdef = 1
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/output0.def"
|
||||
Content-Type: text/plain
|
||||
|
||||
comment ""
|
||||
position -1.13898e-08 2.03328
|
||||
connectornextid 1
|
||||
flags = lock off model off template off footprint off xray off bypass off display off render on highlight off unload off savedata off compress on colordefault on exposed on debug off
|
||||
outputsNamed3
|
||||
{
|
||||
}
|
||||
inputsNamed3
|
||||
{
|
||||
0 reference 0 1 "input1"
|
||||
}
|
||||
inputs
|
||||
{
|
||||
0 reference 0 1
|
||||
}
|
||||
stat
|
||||
{
|
||||
create -1
|
||||
modify -1
|
||||
author Maqina-05@Maqina-05
|
||||
access 0777
|
||||
}
|
||||
color UT_Color RGB 0.8 0.8 0.8
|
||||
delscript ""
|
||||
exprlanguage hscript
|
||||
end
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/output0.parm"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
version 0.8
|
||||
outputidx [ 0 locks=0 ] ( 0 )
|
||||
modifiedprims [ 0 locks=0 ] ( "`lopinputprims(\".\", 0)`" )
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/output0.userdata"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
"___Version___":{
|
||||
"type":"string",
|
||||
"value":"___EXTERNAL___"
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.init"
|
||||
Content-Type: text/plain
|
||||
|
||||
type = reference::2.0
|
||||
matchesdef = 1
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.def"
|
||||
Content-Type: text/plain
|
||||
|
||||
comment ""
|
||||
position -0.00125004 4.19692
|
||||
connectornextid 2
|
||||
flags = lock off model off template off footprint off xray off bypass off display off render off highlight off unload off savedata off compress on colordefault on exposed on debug off
|
||||
outputsNamed3
|
||||
{
|
||||
0 "output1"
|
||||
}
|
||||
inputsNamed3
|
||||
{
|
||||
1 warn_no_representation_set 1 1 "input1"
|
||||
}
|
||||
inputs
|
||||
{
|
||||
0 warn_no_representation_set 0 1
|
||||
}
|
||||
stat
|
||||
{
|
||||
create -1
|
||||
modify -1
|
||||
author Maqina-05@Maqina-05
|
||||
access 0777
|
||||
}
|
||||
color UT_Color RGB 0.8 0.8 0.8
|
||||
delscript ""
|
||||
exprlanguage hscript
|
||||
end
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.editableinputdata"
|
||||
Content-Type: text/plain
|
||||
|
||||
[
|
||||
{
|
||||
}
|
||||
]
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.chn"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
channel primpath1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
defaultString = \"/character\"
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = chs(\"../primpath1\") }
|
||||
}
|
||||
channel reftype1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
defaultString = \"file\"
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = chs(\"../reftype1\") }
|
||||
}
|
||||
channel instanceable1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = ch(\"../instanceable1\") }
|
||||
}
|
||||
channel filerefprim1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
defaultString = \"automaticPrim\"
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = chs(\"../filerefprim1\") }
|
||||
}
|
||||
channel filerefprimpath1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
defaultString = \"\"
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = chs(\"../filerefprimpath1\") }
|
||||
}
|
||||
channel timeoffset1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = ch(\"../timeoffset1\") }
|
||||
}
|
||||
channel timescale1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
default = 1
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 value = 1 1 expr = ch(\"../timescale1\") }
|
||||
}
|
||||
channel reload {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
flags = 0
|
||||
start = 40
|
||||
segment { length = 0 expr = ch(\"../reload\") }
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.parm"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
version 0.8
|
||||
main_switcher [ 0 locks=0 ] ( 0 0 0 )
|
||||
enable [ 0 locks=0 ] ( "on" )
|
||||
input_group [ 0 locks=0 ] ( 0 )
|
||||
primpath [ 0 locks=0 ] ( /`@sourcename` )
|
||||
createprims [ 0 locks=0 ] ( "on" )
|
||||
primcount [ 0 locks=0 ] ( 1 )
|
||||
reftype [ 0 locks=0 ] ( file )
|
||||
instanceable [ 0 locks=0 ] ( "off" )
|
||||
refprim [ 0 locks=0 ] ( automaticPrim )
|
||||
refprimpath [ 0 locks=0 ] ( automaticPrim )
|
||||
files_group [ 0 locks=0 ] ( 1 )
|
||||
num_files [ 0 locks=0 ] ( 1 )
|
||||
reload [ 0 locks=0 ] ( [ reload 0 ] )
|
||||
primkind [ 0 locks=0 ] ( "" )
|
||||
parentprimtype [ 0 locks=0 ] ( UsdGeomXform )
|
||||
handlemissingfiles [ 0 locks=0 ] ( error )
|
||||
preop [ 0 locks=0 ] ( none )
|
||||
refeditop [ 0 locks=0 ] ( prependfront )
|
||||
enable1 [ 0 locks=0 ] ( "on" )
|
||||
parameterorder1 [ 0 locks=0 ] ( "filefirst" )
|
||||
createprims1 [ 0 locks=0 ] ( "on" )
|
||||
primpath1 [ 0 locks=0 ] ( [ primpath1 /`@sourcename` ] )
|
||||
primcount1 [ 0 locks=0 ] ( 1 )
|
||||
reftype1 [ 0 locks=0 ] ( [ reftype1 file ] )
|
||||
instanceable1 [ 0 locks=0 ] ( [ instanceable1 0 ] )
|
||||
filepath1 [ 0 locks=0 ] ( `chs(\"../file\")` )
|
||||
filerefprim1 [ 0 locks=0 ] ( [ filerefprim1 automaticPrim ] )
|
||||
filerefprimpath1 [ 0 locks=0 ] ( [ filerefprimpath1 "" ] )
|
||||
timeoffset1 [ 0 locks=0 ] ( [ timeoffset1 0 ] )
|
||||
timescale1 [ 0 locks=0 ] ( [ timescale1 1 ] )
|
||||
file_spacer1 [ 0 locks=0 ] ( )
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/reference.userdata"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
"___Version___":{
|
||||
"type":"string",
|
||||
"value":"___EXTERNAL___"
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/warn_no_representation_set.init"
|
||||
Content-Type: text/plain
|
||||
|
||||
type = error
|
||||
matchesdef = 1
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/warn_no_representation_set.def"
|
||||
Content-Type: text/plain
|
||||
|
||||
comment ""
|
||||
position -1.13898e-08 5.20999
|
||||
connectornextid 2
|
||||
flags = lock off model off template off footprint off xray off bypass off display on render off highlight off unload off savedata off compress on colordefault on exposed on debug off
|
||||
outputsNamed3
|
||||
{
|
||||
1 "output1"
|
||||
}
|
||||
inputsNamed3
|
||||
{
|
||||
0 (0) "" 1 "input1"
|
||||
}
|
||||
inputs
|
||||
{
|
||||
0 (0) 0 1
|
||||
}
|
||||
stat
|
||||
{
|
||||
create -1
|
||||
modify -1
|
||||
author User@HP-Z820-03
|
||||
access 0777
|
||||
}
|
||||
color UT_Color RGB 0.8 0.8 0.8
|
||||
delscript ""
|
||||
exprlanguage hscript
|
||||
end
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/warn_no_representation_set.chn"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
channel enable1 {
|
||||
lefttype = extend
|
||||
righttype = extend
|
||||
flags = 0
|
||||
start = 39.800000000000004
|
||||
segment { length = 0 expr = "if(ch(\"../representation\"), 0, 1)" }
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/warn_no_representation_set.parm"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
version 0.8
|
||||
numerror [ 0 locks=0 ] ( 1 )
|
||||
errormsg1 [ 0 locks=0 ] ( `chs(\"../load_message\")` )
|
||||
severity1 [ 0 locks=0 ] ( "warn" )
|
||||
enable1 [ 0 locks=0 ] ( [ enable1 0 ] )
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot/warn_no_representation_set.userdata"
|
||||
Content-Type: text/plain
|
||||
|
||||
{
|
||||
"___Version___":{
|
||||
"type":"string",
|
||||
"value":"___EXTERNAL___"
|
||||
}
|
||||
}
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.order"
|
||||
Content-Type: text/plain
|
||||
|
||||
3
|
||||
output0
|
||||
reference
|
||||
warn_no_representation_set
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY
|
||||
Content-Disposition: attachment; filename="hdaroot.net"
|
||||
Content-Type: text/plain
|
||||
|
||||
1
|
||||
|
||||
--HOUDINIMIMEBOUNDARY0xD3ADD339-0x00000F49-0x56B122C9-0x00000001HOUDINIMIMEBOUNDARY--
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"hdaroot/warn_no_representation_set.def":1711565807,
|
||||
"hdaroot/reference.def":1711565598,
|
||||
"hdaroot/output0.def":1708980807,
|
||||
"hdaroot.def":1717451686
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
""
|
||||
Contents.mime Contents.mime
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
# Automatically generated script
|
||||
\set noalias = 1
|
||||
#
|
||||
# Creation script for ayon::lop_import::1.0 operator
|
||||
#
|
||||
|
||||
if ( "$arg1" == "" ) then
|
||||
echo This script is intended as a creation script
|
||||
exit
|
||||
endif
|
||||
|
||||
# Node $arg1 (ayon::Lop/lop_import::1.0)
|
||||
opexprlanguage -s hscript $arg1
|
||||
opuserdata -n '___Version___' -v '' $arg1
|
||||
opuserdata -n 'wirestyle' -v 'rounded' $arg1
|
||||
|
|
@ -0,0 +1,345 @@
|
|||
# Dialog script for ayon::lop_import::1.0 automatically generated
|
||||
|
||||
{
|
||||
name ayon::lop_import::1.0
|
||||
script load_asset::1.0
|
||||
label "Load Asset"
|
||||
|
||||
help {
|
||||
""
|
||||
}
|
||||
|
||||
inputlabel 1 "Input Stage"
|
||||
inputlabel 2 "Input 2"
|
||||
inputlabel 3 "Input 3"
|
||||
inputlabel 4 "Input 4"
|
||||
|
||||
groupsimple {
|
||||
name "info2"
|
||||
label "Info"
|
||||
parmtag { "script_callback" "hou.phm().refresh_available_versions(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
|
||||
parm {
|
||||
name "assetinfo_labelparm"
|
||||
label "Heading"
|
||||
type label
|
||||
default { "Choose Product" }
|
||||
parmtag { "sidefx::look" "heading" }
|
||||
}
|
||||
parm {
|
||||
name "project_name"
|
||||
label "Project"
|
||||
type string
|
||||
default { "$AYON_PROJECT_NAME" }
|
||||
parmtag { "script_action" "from ayon_houdini.api.hda_utils import select_folder_path;select_folder_path(kwargs['node'])" }
|
||||
parmtag { "script_action_icon" "BUTTONS_reselect" }
|
||||
parmtag { "script_callback" "hou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "folder_path"
|
||||
label "Folder Path"
|
||||
type string
|
||||
default { "$AYON_FOLDER_PATH" }
|
||||
parmtag { "script_action" "from ayon_houdini.api.hda_utils import select_folder_path;select_folder_path(kwargs['node'])" }
|
||||
parmtag { "script_action_icon" "BUTTONS_reselect" }
|
||||
parmtag { "script_callback" "hou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "product_type"
|
||||
label "Product Type"
|
||||
type string
|
||||
default { "usd" }
|
||||
}
|
||||
parm {
|
||||
name "product_name"
|
||||
label "Product"
|
||||
type string
|
||||
default { "usdAsset" }
|
||||
menureplace {
|
||||
[ "products = hou.phm().get_available_products(kwargs['node'])" ]
|
||||
[ "" ]
|
||||
[ "result = []" ]
|
||||
[ "for product in products:" ]
|
||||
[ " result.append(product)" ]
|
||||
[ " result.append(product)" ]
|
||||
[ " " ]
|
||||
[ "return result" ]
|
||||
language python
|
||||
}
|
||||
parmtag { "script_callback" "hou.phm().set_to_latest_version(kwargs['node'])\nhou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "version"
|
||||
label "Version"
|
||||
type string
|
||||
default { "" }
|
||||
disablewhen "{ representation_old == \"\" }"
|
||||
menureplace {
|
||||
[ "versions = hou.phm().get_available_versions(kwargs['node'])" ]
|
||||
[ "" ]
|
||||
[ "result = []" ]
|
||||
[ "for version in versions:" ]
|
||||
[ " result.append(str(version))" ]
|
||||
[ " result.append(f\"v{version:03d}\")" ]
|
||||
[ " " ]
|
||||
[ "return result" ]
|
||||
language python
|
||||
}
|
||||
parmtag { "script_callback" "hou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "representation_name"
|
||||
label "Representation"
|
||||
type string
|
||||
default { "usd" }
|
||||
parmtag { "script_callback" "hou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "load_refresh"
|
||||
label "Refresh"
|
||||
type button
|
||||
joinnext
|
||||
default { "0" }
|
||||
help "Click to refresh and retry applying the product load parameters to load the correct file"
|
||||
parmtag { "button_icon" "" }
|
||||
parmtag { "script_callback" "hou.phm().on_representation_parms_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "load_message"
|
||||
label "Message"
|
||||
type label
|
||||
default { "" }
|
||||
hidewhen "{ load_message == \"\" }"
|
||||
parmtag { "sidefx::look" "block" }
|
||||
}
|
||||
parm {
|
||||
name "sepparm"
|
||||
label "Separator"
|
||||
type separator
|
||||
default { "" }
|
||||
}
|
||||
parm {
|
||||
name "reload"
|
||||
label "Reload Files"
|
||||
type button
|
||||
default { "0" }
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "file"
|
||||
label "File"
|
||||
type string
|
||||
default { "" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "primpath1"
|
||||
label "Primitive Root"
|
||||
type string
|
||||
default { "`chs(\"folder_path\")`/$OS" }
|
||||
menureplace {
|
||||
[ "opmenu -l -a reference_character primpath1" ]
|
||||
}
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_action" "import loputils\nloputils.selectPrimsInParm(kwargs, False)" }
|
||||
parmtag { "script_action_help" "Select a primitive in the Scene Viewer or Scene Graph Tree pane.\nCtrl-click to select using the primitive picker dialog.\nAlt-click to toggle movement of the display flag." }
|
||||
parmtag { "script_action_icon" "BUTTONS_reselect" }
|
||||
parmtag { "sidefx::usdpathtype" "prim" }
|
||||
}
|
||||
groupcollapsible {
|
||||
name "extra_options"
|
||||
label "Load Options"
|
||||
|
||||
parm {
|
||||
name "reftype1"
|
||||
label "Reference Type"
|
||||
type string
|
||||
default { "file" }
|
||||
menu {
|
||||
"file" "Reference File"
|
||||
"payload" "Payload File"
|
||||
}
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "instanceable1"
|
||||
label "Make Instanceable"
|
||||
type toggle
|
||||
default { "off" }
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "filerefprim1"
|
||||
label "Reference Primitive"
|
||||
type string
|
||||
default { "automaticPrim" }
|
||||
hidewhen "{ reftype1 == prim } { reftype1 == inherit } { reftype1 == specialize }"
|
||||
menu {
|
||||
"automaticPrim" "Reference Automatically Chosen Primitive"
|
||||
"defaultPrim" "Reference Default Primitive"
|
||||
"" "Reference Specific Primitive"
|
||||
}
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "filerefprimpath1"
|
||||
label "Reference Primitive Path"
|
||||
type string
|
||||
default { "" }
|
||||
disablewhen "{ filerefprim1 != \"\" reftype1 != prim reftype1 != inherit reftype1 != specialize }"
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_action" "import loputils\nnode = kwargs['node']\nparm = kwargs['parmtuple'][0]\nreftype = node.evalParm(parm.name().replace(\n 'filerefprimpath', 'reftype'))\nif reftype in ('prim', 'inherit', 'specialize'):\n prims = loputils.selectPrimsInParm(kwargs, True)\nelse:\n parm = node.parm(parm.name().replace(\n 'filerefprimpath', 'filepath'))\n prims = loputils.selectPrimsInParmFromFile(kwargs, False,\n parm.evalAsString().strip('\\'\"'))" }
|
||||
parmtag { "script_action_help" "Select a primitive from a primitive picker dialog." }
|
||||
parmtag { "script_action_icon" "BUTTONS_reselect" }
|
||||
parmtag { "sidefx::usdpathinput" "if(index(\"prim inherit specialize\", chs(\"reftype#\")) >= 0, 0, -1)" }
|
||||
parmtag { "sidefx::usdpathtype" "prim" }
|
||||
}
|
||||
parm {
|
||||
name "timeoffset1"
|
||||
label "Time Offset (in Frames)"
|
||||
type float
|
||||
default { "0" }
|
||||
range { -100 100 }
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "timescale1"
|
||||
label "Time Scale"
|
||||
type float
|
||||
default { "1" }
|
||||
range { 0 5 }
|
||||
parmtag { "autoscope" "0000000000000000" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
groupcollapsible {
|
||||
name "info_display2"
|
||||
label "Info Display"
|
||||
|
||||
parm {
|
||||
name "show_thumbnail"
|
||||
label "Show Entity Thumbnail"
|
||||
type toggle
|
||||
joinnext
|
||||
default { "0" }
|
||||
parmtag { "script_callback" "hou.phm().on_thumbnail_show_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "thumbnail_size"
|
||||
label "Size"
|
||||
type float
|
||||
joinnext
|
||||
default { "2" }
|
||||
hidewhen "{ show_thumbnail == 0 }"
|
||||
range { 0 10 }
|
||||
parmtag { "script_callback" "hou.phm().on_thumbnail_size_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "thumbnail_cache_dir"
|
||||
label "Thumbnail Cache Dir"
|
||||
type directory
|
||||
invisible
|
||||
default { "$JOB/.houdini_loader_thumbnails" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "thumbnail_padding"
|
||||
label "Padding"
|
||||
type float
|
||||
invisible
|
||||
default { "1" }
|
||||
range { 0 10 }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "thumbnail_offset"
|
||||
label "Offset"
|
||||
type vector2
|
||||
size 2
|
||||
default { "0" "0.35" }
|
||||
hidewhen "{ show_thumbnail == 0 }"
|
||||
range { -1 1 }
|
||||
parmtag { "script_callback" "hou.phm().on_thumbnail_size_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "show_pipeline_parms"
|
||||
label "Show Pipeline Parms"
|
||||
type toggle
|
||||
default { "0" }
|
||||
parmtag { "script_callback" "hou.phm().on_thumbnail_show_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
}
|
||||
|
||||
group {
|
||||
name "ayon_folder0"
|
||||
label "Ayon"
|
||||
hidewhen "{ show_pipeline_parms == 0 }"
|
||||
|
||||
parm {
|
||||
name "name"
|
||||
label "Name"
|
||||
type label
|
||||
default { "$OS" }
|
||||
}
|
||||
parm {
|
||||
name "namespace"
|
||||
label "Namespace"
|
||||
type label
|
||||
default { "`opfullpath(\".\")`" }
|
||||
}
|
||||
parm {
|
||||
name "loader"
|
||||
label "Loader"
|
||||
type label
|
||||
default { "LOPLoadAssetLoader" }
|
||||
}
|
||||
parm {
|
||||
name "id"
|
||||
label "ID"
|
||||
type label
|
||||
default { "pyblish.avalon.container" }
|
||||
}
|
||||
parm {
|
||||
name "representation"
|
||||
label "Representation ID"
|
||||
type string
|
||||
default { "" }
|
||||
parmtag { "script_callback" "hou.phm().on_representation_id_changed(kwargs['node'])" }
|
||||
parmtag { "script_callback_language" "python" }
|
||||
}
|
||||
parm {
|
||||
name "version_name"
|
||||
label "Current Version Label"
|
||||
type label
|
||||
invisible
|
||||
default { "" }
|
||||
}
|
||||
parm {
|
||||
name "subset_name"
|
||||
label "Subset (backwards compatibility)"
|
||||
type label
|
||||
invisible
|
||||
default { "`chs(\"product_name\")`" }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
{
|
||||
"AYON_icon.png/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[0,0]
|
||||
},
|
||||
"AYON_icon.png/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"AYON_icon.png/IsPython":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"AYON_icon.png/IsScript":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"AYON_icon.png/Source":{
|
||||
"type":"string",
|
||||
"value":"C:/Users/Maqina-05/Desktop/AYON_icon.png"
|
||||
},
|
||||
"OnCreated/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[5,29]
|
||||
},
|
||||
"OnCreated/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"OnCreated/IsPython":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnCreated/IsScript":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnCreated/Source":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
},
|
||||
"OnDeleted/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[1,15]
|
||||
},
|
||||
"OnDeleted/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"OnDeleted/IsPython":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnDeleted/IsScript":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnDeleted/Source":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
},
|
||||
"OnLoaded/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[9,76]
|
||||
},
|
||||
"OnLoaded/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"OnLoaded/IsPython":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnLoaded/IsScript":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnLoaded/Source":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
},
|
||||
"OnNameChanged/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[1,15]
|
||||
},
|
||||
"OnNameChanged/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"OnNameChanged/IsPython":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnNameChanged/IsScript":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"OnNameChanged/Source":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
},
|
||||
"PythonModule/Cursor":{
|
||||
"type":"intarray",
|
||||
"value":[10,1]
|
||||
},
|
||||
"PythonModule/IsExpr":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"PythonModule/IsPython":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"PythonModule/IsScript":{
|
||||
"type":"bool",
|
||||
"value":true
|
||||
},
|
||||
"PythonModule/Source":{
|
||||
"type":"string",
|
||||
"value":""
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"nodeconntype":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
},
|
||||
"nodeparmtype":{
|
||||
"type":"bool",
|
||||
"value":false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
warn_no_representation_set reference
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
node = kwargs["node"]
|
||||
hda_module = node.hdaModule()
|
||||
hda_module.setup_flag_changed_callback(node)
|
||||
|
||||
node.parm("product_type").lock(True)
|
||||
node.parm("file").lock(True)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
from ayon_houdini.api.lib import remove_all_thumbnails
|
||||
|
||||
|
||||
# Clear thumbnails
|
||||
node = kwargs["node"]
|
||||
remove_all_thumbnails(node)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
node = kwargs["node"]
|
||||
hda_module = node.hdaModule()
|
||||
hda_module.setup_flag_changed_callback(node)
|
||||
|
||||
|
||||
# Duplicate callback
|
||||
def on_duplicate():
|
||||
"""Duplicate thumbnail on node duplicate"""
|
||||
if node.evalParm("show_thumbnail") and node.evalParm("representation"):
|
||||
hda_module.on_representation_id_changed(node)
|
||||
|
||||
|
||||
if not hou.hipFile.isLoadingHipFile():
|
||||
on_duplicate()
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
from ayon_houdini.api.hda_utils import (
|
||||
keep_background_images_linked
|
||||
)
|
||||
|
||||
|
||||
node = kwargs["node"]
|
||||
old_name = kwargs["old_name"]
|
||||
keep_background_images_linked(node, old_name)
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
from ayon_houdini.api.hda_utils import (
|
||||
on_thumbnail_show_changed,
|
||||
on_thumbnail_size_changed,
|
||||
on_representation_id_changed,
|
||||
on_representation_parms_changed,
|
||||
setup_flag_changed_callback,
|
||||
get_available_versions,
|
||||
get_available_products,
|
||||
set_to_latest_version
|
||||
)
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
""
|
||||
DialogScript DialogScript
|
||||
CreateScript CreateScript
|
||||
InternalFileOptions InternalFileOptions
|
||||
Contents.gz Contents.gz
|
||||
TypePropertiesOptions TypePropertiesOptions
|
||||
Tools.shelf Tools.shelf
|
||||
Help Help
|
||||
IconImage IconImage
|
||||
MessageNodes MessageNodes
|
||||
PythonModule PythonModule
|
||||
OnDeleted OnDeleted
|
||||
OnNameChanged OnNameChanged
|
||||
OnLoaded OnLoaded
|
||||
OnCreated OnCreated
|
||||
ExtraFileOptions ExtraFileOptions
|
||||
AYON__icon.png AYON_icon.png
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shelfDocument>
|
||||
<!-- This file contains definitions of shelves, toolbars, and tools.
|
||||
It should not be hand-edited when it is being used by the application.
|
||||
Note, that two definitions of the same element are not allowed in
|
||||
a single file. -->
|
||||
<tool name="$HDA_DEFAULT_TOOL" label="$HDA_LABEL" icon="$HDA_ICON">
|
||||
<toolMenuContext name="viewer">
|
||||
<contextNetType>LOP</contextNetType>
|
||||
</toolMenuContext>
|
||||
<toolMenuContext name="network">
|
||||
<contextOpType>$HDA_TABLE_AND_NAME</contextOpType>
|
||||
</toolMenuContext>
|
||||
<toolSubmenu>AYON</toolSubmenu>
|
||||
<script scriptType="python"><![CDATA[import loptoolutils
|
||||
loptoolutils.genericTool(kwargs, '$HDA_NAME')]]></script>
|
||||
</tool>
|
||||
</shelfDocument>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
CheckExternal := 1;
|
||||
ContentsCompressionType := 1;
|
||||
ForbidOutsideParms := 1;
|
||||
GzipContents := 1;
|
||||
LockContents := 1;
|
||||
MakeDefault := 1;
|
||||
ParmsFromVfl := 0;
|
||||
PrefixDroppedParmLabel := 0;
|
||||
PrefixDroppedParmName := 0;
|
||||
SaveCachedCode := 0;
|
||||
SaveIcon := 1;
|
||||
SaveSpareParms := 0;
|
||||
UnlockOnCreate := 0;
|
||||
UseDSParms := 1;
|
||||
Loading…
Add table
Add a link
Reference in a new issue