diff --git a/openpype/hosts/max/api/lib.py b/openpype/hosts/max/api/lib.py index 4fb750d91b..f1d1f91dd1 100644 --- a/openpype/hosts/max/api/lib.py +++ b/openpype/hosts/max/api/lib.py @@ -6,6 +6,14 @@ from pymxs import runtime as rt from typing import Union import contextlib +from openpype.client import ( + get_project, + get_asset_by_name +) +from openpype.pipeline import legacy_io + +from openpype.pipeline.context_tools import get_current_project_asset + JSON_PREFIX = "JSON::" @@ -157,6 +165,125 @@ def get_multipass_setting(project_setting=None): ["multipass"]) +def set_scene_resolution(width, height): + """Set the render resolution + + Args: + width(int): value of the width + height(int): value of the height + + Returns: + None + + """ + rt.renderWidth = width + rt.renderHeight = height + + +def reset_scene_resolution(): + """Apply the scene resolution from the project definition + + scene resolution can be overwritten by an asset if the asset.data contains + any information regarding scene resolution . + + Returns: + None + """ + project_name = legacy_io.active_project() + project_doc = get_project(project_name) + project_data = project_doc["data"] + asset_data = get_current_project_asset()["data"] + + # Set project resolution + width_key = "resolutionWidth" + height_key = "resolutionHeight" + proj_width_key = project_data.get(width_key, 1920) + proj_height_key = project_data.get(height_key, 1080) + + width = asset_data.get(width_key, proj_width_key) + height = asset_data.get(height_key, proj_height_key) + + set_scene_resolution(width, height) + + +def get_frame_range(): + """Get the current assets frame range and handles.""" + # Set frame start/end + project_name = legacy_io.active_project() + asset_name = legacy_io.Session["AVALON_ASSET"] + asset = get_asset_by_name(project_name, asset_name) + + frame_start = asset["data"].get("frameStart") + frame_end = asset["data"].get("frameEnd") + # Backwards compatibility + if frame_start is None or frame_end is None: + frame_start = asset["data"].get("edit_in") + frame_end = asset["data"].get("edit_out") + + if frame_start is None or frame_end is None: + return + + handles = asset["data"].get("handles") or 0 + handle_start = asset["data"].get("handleStart") + if handle_start is None: + handle_start = handles + + handle_end = asset["data"].get("handleEnd") + if handle_end is None: + handle_end = handles + + return { + "frameStart": frame_start, + "frameEnd": frame_end, + "handleStart": handle_start, + "handleEnd": handle_end + } + + +def reset_frame_range(fps=True): + """Set frame range to current asset + + Args: + animationRange: A System Global variable which lets you get and + set an Interval value that defines the start and end frames + of the Active Time Segment. + frameRate: A System Global variable which lets you get + and set an Integer value that defines the current + scene frame rate in frames-per-second. + """ + if fps: + fps_number = float(legacy_io.Session.get("AVALON_FPS", + 25)) + rt.frameRate = fps_number + + frame_range = get_frame_range() + + frame_start = frame_range["frameStart"] - int(frame_range["handleStart"]) + frame_end = frame_range["frameEnd"] + int(frame_range["handleEnd"]) + + frange_cmd = f"animationRange = interval {frame_start} {frame_end}" + + rt.execute(frange_cmd) + + +def set_context_setting(): + """Apply the project settings from the project definition + + Settings can be overwritten by an asset if the asset.data contains + any information regarding those settings. + + Examples of settings: + frame range + resolution + + Returns: + None + """ + reset_scene_resolution() + + reset_frame_range() + + def get_max_version(): """ Args: diff --git a/openpype/hosts/max/api/menu.py b/openpype/hosts/max/api/menu.py index 5c273b49b4..fdac5eba09 100644 --- a/openpype/hosts/max/api/menu.py +++ b/openpype/hosts/max/api/menu.py @@ -4,7 +4,7 @@ from qtpy import QtWidgets, QtCore from pymxs import runtime as rt from openpype.tools.utils import host_tools - +from openpype.hosts.max.api import lib class OpenPypeMenu(object): """Object representing OpenPype menu. @@ -107,6 +107,17 @@ class OpenPypeMenu(object): workfiles_action = QtWidgets.QAction("Work Files...", openpype_menu) workfiles_action.triggered.connect(self.workfiles_callback) openpype_menu.addAction(workfiles_action) + + openpype_menu.addSeparator() + + res_action = QtWidgets.QAction("Set Resolution", openpype_menu) + res_action.triggered.connect(self.resolution_callback) + openpype_menu.addAction(res_action) + + frame_action = QtWidgets.QAction("Set Frame Range", openpype_menu) + frame_action.triggered.connect(self.frame_range_callback) + openpype_menu.addAction(frame_action) + return openpype_menu def load_callback(self): @@ -128,3 +139,11 @@ class OpenPypeMenu(object): def workfiles_callback(self): """Callback to show Workfiles tool.""" host_tools.show_workfiles(parent=self.main_widget) + + def resolution_callback(self): + """Callback to reset scene resolution""" + return lib.reset_scene_resolution() + + def frame_range_callback(self): + """Callback to reset frame range""" + return lib.reset_frame_range() diff --git a/openpype/hosts/max/api/pipeline.py b/openpype/hosts/max/api/pipeline.py index f8a7b8ea5c..dacc402318 100644 --- a/openpype/hosts/max/api/pipeline.py +++ b/openpype/hosts/max/api/pipeline.py @@ -50,6 +50,11 @@ class MaxHost(HostBase, IWorkfileHost, ILoadHost, INewPublisher): self._has_been_setup = True + def context_setting(): + return lib.set_context_setting() + rt.callbacks.addScript(rt.Name('systemPostNew'), + context_setting) + def has_unsaved_changes(self): # TODO: how to get it from 3dsmax? return True