Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Local/seif integrate #6246

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
8ef0508
:sparkles: working 3dequalizer integration
antirotor Sep 13, 2023
0c4e6d7
:bug: fix workfile tool menu label
antirotor Sep 13, 2023
5f3dc1b
:package: add AYON addon settings
antirotor Sep 15, 2023
a27dcb9
:package: add 3dequalizer to applications addon
antirotor Sep 15, 2023
b891441
:bug: fix the settings for 3dequalizer
antirotor Sep 15, 2023
f48340d
:art: equalizer project settings for openpypy
antirotor Sep 15, 2023
930990d
:construction: initial work on loader and creator plugins
antirotor Sep 15, 2023
304cd10
:construction: publishing wip
antirotor Sep 19, 2023
8528816
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Oct 9, 2023
820553f
:bug: fix context saving
antirotor Oct 17, 2023
10aeae9
:bug: fix content data saving
antirotor Oct 20, 2023
2195fc7
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Oct 31, 2023
82503e5
:recycle: update UI and some work on creators
antirotor Nov 1, 2023
fc5e1d8
:construction: wip on matchmove extraction
antirotor Nov 2, 2023
ac5ccbf
:art: finish maya extraction
antirotor Nov 3, 2023
3aa5136
:bug: handle logging error for equalizer
antirotor Nov 3, 2023
6e90f97
:construction: start of nuke extractor
antirotor Nov 3, 2023
5619080
:recycle: calm down a :dog: a little bit
antirotor Nov 6, 2023
0dc6af9
:recycle: calm :dog: a little more
antirotor Nov 6, 2023
0288f15
:recycle: add todo
antirotor Nov 6, 2023
bae50b7
:page_facing_up: fill in license placeholders
antirotor Nov 6, 2023
5b9accc
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Nov 7, 2023
830e332
:recycle: refactor nuke extraction script
antirotor Nov 7, 2023
871951e
Merge branch 'develop' into feature/OP-6032_3dequalizer-integration
antirotor Nov 7, 2023
6322c58
:bug: fix representation file names
antirotor Nov 8, 2023
b610a25
:recycle: change inheritance
antirotor Nov 8, 2023
af6be5f
:hammer: add 3dequalizer to collection
antirotor Nov 8, 2023
ab79ac1
Merge remote-tracking branch 'origin/feature/OP-6032_3dequalizer-inte…
antirotor Nov 8, 2023
a043659
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Nov 20, 2023
eff71bb
:bug: fix nuke script typos
antirotor Nov 20, 2023
49032a3
:recycle: increase refresh time
antirotor Nov 20, 2023
2b6da15
:art: add heartbeat interval to the settings
antirotor Nov 23, 2023
a4ff4cd
:bug: fix value type
antirotor Nov 23, 2023
0172858
:boom: monkey-patching nuke export UI options
antirotor Nov 23, 2023
9ec9b13
:art: add support for publishing and loading LDPK data
antirotor Nov 24, 2023
d65d105
:recycle: remove unused import
antirotor Nov 24, 2023
4aff34a
:art: add matchmove loader support
antirotor Nov 24, 2023
68ddf73
:recycle: change matchmove loader so it containerize properly
antirotor Nov 24, 2023
3104e40
:recycle: handle undefined loaders more gracefully
antirotor Nov 24, 2023
0c0e956
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Dec 12, 2023
cc2689b
:dog: hound fixes
antirotor Dec 12, 2023
bfed05c
Merge remote-tracking branch 'origin/develop' into feature/OP-6032_3d…
antirotor Feb 2, 2024
f06e13d
Merge branch 'develop' into feature/OP-6032_3dequalizer-integration
antirotor Feb 22, 2024
8798636
:art: add support of 3de4 home dir as env
antirotor Feb 22, 2024
e4e64dc
Merge branch 'feature/OP-6032_3dequalizer-integration' of https://git…
Mar 13, 2024
e2622cf
integrate 3de4 R5 with py2.7
Mar 14, 2024
96aa9be
fix: 3de4 r5 icon
Mar 14, 2024
92885dc
update gitignore
eng-EslamEzzat Mar 17, 2024
9c37b5d
add pyside to py2 with large file
eng-EslamEzzat Mar 17, 2024
b4a681c
Merge branch 'ynput:develop' into develop
eng-EslamEzzat Mar 18, 2024
a067762
Merge branch 'develop' of https://github.com/eng-EslamEzzat/OpenPype …
eng-EslamEzzat Mar 18, 2024
b671e71
pyside in qtpy
eng-EslamEzzat Mar 18, 2024
af9b3f7
pysice int
seifibrahim32 Mar 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -119,3 +119,4 @@ tools/dev_*
########
/openpype/addons/*
!/openpype/addons/README.md
test.py
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files
# - id: check-added-large-files
- id: no-commit-to-branch
args: [ '--pattern', '^(?!((release|enhancement|feature|bugfix|documentation|tests|local|chore)\/[a-zA-Z0-9\-_]+)$).*' ]
9 changes: 9 additions & 0 deletions openpype/hosts/equalizer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from .addon import (
EqualizerAddon,
EQUALIZER_HOST_DIR,
)

__all__ = [
"EqualizerAddon",
"EQUALIZER_HOST_DIR",
]
40 changes: 40 additions & 0 deletions openpype/hosts/equalizer/addon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import os
from openpype.modules import OpenPypeModule, IHostAddon

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


class EqualizerAddon(OpenPypeModule, IHostAddon):
name = "equalizer"
host_name = "equalizer"
heartbeat = 500

def initialize(self, module_settings):
self.heartbeat = module_settings.get("heartbeat_interval", 500)
self.enabled = True

def add_implementation_envs(self, env, _app):
# 3dEqualizer utilize TDE4_ROOT for its root directory
# and PYTHON_CUSTOM_SCRIPTS_3DE4 as a colon separated list of
# directories to look for additional python scripts.
# (Windows: list is separated by semicolons).
# Ad

startup_path = os.path.join(EQUALIZER_HOST_DIR, "startup")
if "PYTHON_CUSTOM_SCRIPTS_3DE4" in env:
startup_path = os.path.join(
env["PYTHON_CUSTOM_SCRIPTS_3DE4"],
startup_path)

env["PYTHON_CUSTOM_SCRIPTS_3DE4"] = startup_path
env["AYON_TDE4_HEARTBEAT_INTERVAL"] = str(self.heartbeat)

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

def get_workfile_extensions(self):
return [".3de"]
11 changes: 11 additions & 0 deletions openpype/hosts/equalizer/api/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from .host import EqualizerHost
from .plugin import EqualizerCreator, ExtractScriptBase
from .pipeline import Container, maintained_model_selection

__all__ = [
"EqualizerHost",
"EqualizerCreator",
"Container",
"ExtractScriptBase",
"maintained_model_selection",
]
225 changes: 225 additions & 0 deletions openpype/hosts/equalizer/api/host.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
"""
3dequalizer host implementation.

note:
3dequalizer Release 5 uses Python 2.7
"""

import json
import os
import re

from attr import asdict
from attr.exceptions import NotAnAttrsClassError
import pyblish.api
import tde4 # noqa: F401
from qtpy import QtCore, QtWidgets

from openpype.host import HostBase, ILoadHost, IPublishHost, IWorkfileHost
from openpype.hosts.equalizer import EQUALIZER_HOST_DIR
from openpype.pipeline import (
register_creator_plugin_path,
register_loader_plugin_path,
legacy_io
)

CONTEXT_REGEX = re.compile(
r"AYON_CONTEXT::(?P<context>.*?)::AYON_CONTEXT_END",
re.DOTALL)
PLUGINS_DIR = os.path.join(EQUALIZER_HOST_DIR, "plugins")
PUBLISH_PATH = os.path.join(PLUGINS_DIR, "publish")
LOAD_PATH = os.path.join(PLUGINS_DIR, "load")
CREATE_PATH = os.path.join(PLUGINS_DIR, "create")
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "inventory")


class EqualizerHost(HostBase, IWorkfileHost, ILoadHost, IPublishHost):
name = "equalizer"
_instance = None

def __new__(cls):
if not hasattr(cls, "_instance") or not cls._instance:
cls._instance = super(EqualizerHost, cls).__new__(cls)
return cls._instance

def __init__(self):
self._qapp = None
super(EqualizerHost, self).__init__()

def workfile_has_unsaved_changes(self):
"""Return the state of the current workfile.

3DEqualizer returns state as 1 or zero, so we need to invert it.

Returns:
bool: True if the current workfile has unsaved changes.
"""
return not bool(tde4.isProjectUpToDate())

def get_workfile_extensions(self):
return [".3de"]

def save_workfile(self, filepath=None):
result = tde4.saveProject(filepath)
if not bool(result):
raise RuntimeError("Failed to save workfile %s."%filepath)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace around modulo operator


return filepath

def open_workfile(self, filepath):
result = tde4.loadProject(filepath)
if not bool(result):
raise RuntimeError("Failed to open workfile %s."%filepath)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace around modulo operator


return filepath

def get_current_workfile(self):
current_filepath = tde4.getProjectPath()
if not current_filepath:
return None

return current_filepath


def get_overscan(self):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too many blank lines (2)

context = self.get_context_data()
if "overscan" in context:
return context.get("overscan", {})
return {}

def set_overscan(self, overscan_width, overscan_height):
context_data = self.get_context_data()
overscan = self.get_overscan()
if not overscan:
overscan = {
"width": overscan_width,
"height": overscan_height
}
else:
overscan["width"] = overscan_width
overscan["height"] = overscan_height

context_data["overscan"] = overscan
self.update_context_data(context_data, changes={})

def get_containers(self):
context = self.get_context_data()
if context:
return context.get("containers", [])
return []

def add_container(self, container):
context_data = self.get_context_data()
containers = self.get_containers()

for _container in containers:
if _container["name"] == container.name and _container["namespace"] == container.namespace: # noqa: E501
containers.remove(_container)
break

try:
containers.append(asdict(container))
except NotAnAttrsClassError:
print("not an attrs class")
containers.append(container)

context_data["containers"] = containers
self.update_context_data(context_data, changes={})

def get_context_data(self):
"""Get context data from the current workfile.

3Dequalizer doesn't have any custom node or other
place to store metadata, so we store context data in
the project notes encoded as JSON and wrapped in a
special guard string `AYON_CONTEXT::...::AYON_CONTEXT_END`.

Returns:
dict: Context data.
"""

# sourcery skip: use-named-expression
m = re.search(CONTEXT_REGEX, tde4.getProjectNotes())
try:
context = json.loads(m.groupdict()["context"]) if m else {}
except ValueError:
self.log.debug("context data is not valid json")
context = {}

return context

def update_context_data(self, data, changes):
"""Update context data in the current workfile.

Serialize context data as json and store it in the
project notes. If the context data is not found, create
a placeholder there. See `get_context_data` for more info.

Args:
data (dict): Context data.
changes (dict): Changes to the context data.

Raises:
RuntimeError: If the context data is not found.
"""
m = re.search(CONTEXT_REGEX, tde4.getProjectNotes())
if not m:
# context data not found, create empty placeholder
tde4.setProjectNotes("AYON_CONTEXT::::AYON_CONTEXT_END")

original_data = self.get_context_data()

updated_data = original_data.copy()
updated_data.update(data)
update_str = json.dumps(updated_data or {}, indent=4)

tde4.setProjectNotes(
re.sub(
CONTEXT_REGEX,
"AYON_CONTEXT::%s::AYON_CONTEXT_END"%update_str,
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing whitespace around modulo operator

tde4.getProjectNotes()
)
)
tde4.updateGUI()

def install(self):
if not QtCore.QCoreApplication.instance():
app = QtWidgets.QApplication([])
self._qapp = app
self._qapp.setQuitOnLastWindowClosed(False)

pyblish.api.register_plugin_path(PUBLISH_PATH)
pyblish.api.register_host("equalizer")

register_loader_plugin_path(LOAD_PATH)
register_creator_plugin_path(CREATE_PATH)

# heartbeat_interval = os.getenv("AYON_TDE4_HEARTBEAT_INTERVAL") or 500
# tde4.setTimerCallbackFunction(
# "EqualizerHost._timer", int(heartbeat_interval))


def _set_project(self):
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too many blank lines (2)

workdir = legacy_io.Session["AVALON_WORKDIR"]
if os.path.exists(workdir):
projects = []
workdir_files = os.listdir(workdir)
if len(workdir_files) > 0:
for f in os.listdir(workdir):
if legacy_io.Session["AVALON_ASSET"] in f:
projects.append(f)
projects.sort()
tde4.loadProject(os.path.join(workdir, projects[-1]))


@staticmethod
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

too many blank lines (2)

def _timer():
QtWidgets.QApplication.instance().processEvents(
QtCore.QEventLoop.AllEvents)

@classmethod
def get_host(cls):
return cls._instance

def get_main_window(self):
return self._qapp.activeWindow()
38 changes: 38 additions & 0 deletions openpype/hosts/equalizer/api/pipeline.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@

import attr
from openpype.pipeline import AVALON_CONTAINER_ID
import contextlib
import tde4

@attr.s
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

expected 2 blank lines, found 1

class Container(object):
name = attr.ib(default=None)
id = attr.ib(init=False, default=AVALON_CONTAINER_ID)
namespace = attr.ib(default="")
loader = attr.ib(default=None)
representation = attr.ib(default=None)


@contextlib.contextmanager
def maintained_model_selection():
"""Maintain model selection during context."""

point_groups = tde4.getPGroupList()
point_group = next(
(
pg for pg in point_groups
if tde4.getPGroupType(pg) == "CAMERA"
), None
)
selected_models = tde4.get3DModelList(point_group, 1)\
if point_group else []
try:
yield
finally:
if point_group:
# 3 restore model selection
for model in tde4.get3DModelList(point_group, 0):
if model in selected_models:
tde4.set3DModelSelectionFlag(point_group, model, 1)
else:
tde4.set3DModelSelectionFlag(point_group, model, 0)
Loading
Loading