mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-26 05:42:15 +01:00
More WIP refactoring for TextureProcessors
This commit is contained in:
parent
5961d6dfb9
commit
b37c15f582
1 changed files with 148 additions and 147 deletions
|
|
@ -26,37 +26,6 @@ COPY = 1
|
|||
HARDLINK = 2
|
||||
|
||||
|
||||
def _has_arnold():
|
||||
"""Return whether the arnold package is available and can be imported."""
|
||||
try:
|
||||
import arnold # noqa: F401
|
||||
return True
|
||||
except (ImportError, ModuleNotFoundError):
|
||||
return False
|
||||
|
||||
|
||||
def get_redshift_tool(tool_name):
|
||||
"""Path to redshift texture processor.
|
||||
|
||||
On Windows it adds .exe extension if missing from tool argument.
|
||||
|
||||
Args:
|
||||
tool (string): Tool name.
|
||||
|
||||
Returns:
|
||||
str: Full path to redshift texture processor executable.
|
||||
"""
|
||||
redshift_os_path = os.environ["REDSHIFT_COREDATAPATH"]
|
||||
|
||||
redshift_tool_path = os.path.join(
|
||||
redshift_os_path,
|
||||
"bin",
|
||||
tool_name
|
||||
)
|
||||
|
||||
return find_executable(redshift_tool_path)
|
||||
|
||||
|
||||
def find_paths_by_hash(texture_hash):
|
||||
"""Find the texture hash key in the dictionary.
|
||||
|
||||
|
|
@ -75,17 +44,26 @@ def find_paths_by_hash(texture_hash):
|
|||
|
||||
@six.add_metaclass(ABCMeta)
|
||||
class TextureProcessor:
|
||||
|
||||
def __init__(self, log=None):
|
||||
if log is None:
|
||||
log = logging.getLogger(self.__class___.__name__)
|
||||
self.log = log
|
||||
|
||||
@abstractmethod
|
||||
def process(self, filepath):
|
||||
|
||||
def apply_settings(self, system_settings, project_settings):
|
||||
pass
|
||||
|
||||
@abstractmethod
|
||||
def process(self,
|
||||
source,
|
||||
colorspace,
|
||||
color_management,
|
||||
staging_dir):
|
||||
pass
|
||||
|
||||
# TODO: Warning this only supports Py3.3+
|
||||
@staticmethod
|
||||
@abstractmethod
|
||||
def get_extension():
|
||||
pass
|
||||
|
||||
|
|
@ -93,10 +71,11 @@ class TextureProcessor:
|
|||
class MakeRSTexBin(TextureProcessor):
|
||||
"""Make `.rstexbin` using `redshiftTextureProcessor`"""
|
||||
|
||||
def __init__(self):
|
||||
super(MakeRSTexBin, self).__init__()
|
||||
|
||||
def process(self, source, *args):
|
||||
def process(self,
|
||||
source,
|
||||
colorspace,
|
||||
color_management,
|
||||
staging_dir):
|
||||
"""
|
||||
with some default settings.
|
||||
|
||||
|
|
@ -105,24 +84,22 @@ class MakeRSTexBin(TextureProcessor):
|
|||
|
||||
Args:
|
||||
source (str): Path to source file.
|
||||
*args: Additional arguments for `redshiftTextureProcessor`.
|
||||
|
||||
"""
|
||||
if "REDSHIFT_COREDATAPATH" not in os.environ:
|
||||
raise RuntimeError("Must have Redshift available.")
|
||||
|
||||
texture_processor_path = get_redshift_tool("redshiftTextureProcessor")
|
||||
texture_processor_path = self.get_redshift_tool(
|
||||
"redshiftTextureProcessor"
|
||||
)
|
||||
if not texture_processor_path:
|
||||
raise KnownPublishError("Must have Redshift available.",
|
||||
title="Make RSTexBin texture")
|
||||
raise KnownPublishError("Must have Redshift available.")
|
||||
|
||||
subprocess_args = [
|
||||
texture_processor_path,
|
||||
source
|
||||
]
|
||||
|
||||
subprocess_args.extend(args)
|
||||
|
||||
self.log.debug(" ".join(subprocess_args))
|
||||
try:
|
||||
out = run_subprocess(subprocess_args)
|
||||
|
|
@ -131,18 +108,43 @@ class MakeRSTexBin(TextureProcessor):
|
|||
exc_info=True)
|
||||
raise
|
||||
|
||||
# TODO: Implement correct return values
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def get_extension():
|
||||
return ".rstexbin"
|
||||
|
||||
@staticmethod
|
||||
def get_redshift_tool(tool_name):
|
||||
"""Path to redshift texture processor.
|
||||
|
||||
On Windows it adds .exe extension if missing from tool argument.
|
||||
|
||||
Args:
|
||||
tool (string): Tool name.
|
||||
|
||||
Returns:
|
||||
str: Full path to redshift texture processor executable.
|
||||
"""
|
||||
redshift_os_path = os.environ["REDSHIFT_COREDATAPATH"]
|
||||
|
||||
redshift_tool_path = os.path.join(
|
||||
redshift_os_path,
|
||||
"bin",
|
||||
tool_name
|
||||
)
|
||||
|
||||
return find_executable(redshift_tool_path)
|
||||
|
||||
|
||||
class MakeTX(TextureProcessor):
|
||||
def __init__(self):
|
||||
super(MakeTX, self).__init__()
|
||||
|
||||
def process(self, source, destination, *args):
|
||||
def process(self,
|
||||
source,
|
||||
colorspace,
|
||||
color_management,
|
||||
staging_dir):
|
||||
"""Make `.tx` using `maketx` with some default settings.
|
||||
|
||||
The settings are based on default as used in Arnold's
|
||||
|
|
@ -152,8 +154,6 @@ class MakeTX(TextureProcessor):
|
|||
|
||||
Args:
|
||||
source (str): Path to source file.
|
||||
destination (str): Writing destination path.
|
||||
*args: Additional arguments for `maketx`.
|
||||
|
||||
Returns:
|
||||
str: Output of `maketx` command.
|
||||
|
|
@ -164,9 +164,78 @@ class MakeTX(TextureProcessor):
|
|||
maketx_path = get_oiio_tools_path("maketx")
|
||||
|
||||
if not maketx_path:
|
||||
print(
|
||||
"OIIO tool not found in {}".format(maketx_path))
|
||||
raise AssertionError("OIIO tool not found")
|
||||
raise AssertionError(
|
||||
"OIIO 'maketx' tool not found. Result: {}".format(maketx_path)
|
||||
)
|
||||
|
||||
# Define .tx filepath in staging if source file is not .tx
|
||||
fname, ext = os.path.splitext(os.path.basename(source))
|
||||
if ext == ".tx":
|
||||
# TODO: Implement this fallback
|
||||
# Do nothing if the source file is already a .tx file.
|
||||
# return source, COPY, texture_hash, render_colorspace
|
||||
pass
|
||||
|
||||
args = []
|
||||
if color_management["enabled"]:
|
||||
config_path = color_management["config"]
|
||||
if not os.path.exists(config_path):
|
||||
raise RuntimeError("OCIO config not found at: "
|
||||
"{}".format(config_path))
|
||||
|
||||
render_colorspace = color_management["rendering_space"]
|
||||
|
||||
self.log.info("tx: converting colorspace {0} "
|
||||
"-> {1}".format(colorspace,
|
||||
render_colorspace))
|
||||
args.extend(["--colorconvert", colorspace, render_colorspace])
|
||||
args.extend(["--colorconfig", config_path])
|
||||
|
||||
else:
|
||||
# We can't rely on the colorspace attribute when not in color
|
||||
# managed mode because the collected color space is the color space
|
||||
# attribute of the file node which can be any string whatsoever
|
||||
# but only appears disabled in Attribute Editor. We assume we're
|
||||
# always converting to linear/Raw if the source file is assumed to
|
||||
# be sRGB.
|
||||
# TODO Without color management do we even know we can do
|
||||
# "colorconvert" and what config does that end up using since
|
||||
# colorconvert is a OCIO command line flag for maketx.
|
||||
# Also, Raw != linear?
|
||||
render_colorspace = "linear"
|
||||
if self._has_arnold():
|
||||
img_info = image_info(source)
|
||||
color_space = guess_colorspace(img_info)
|
||||
if color_space.lower() == "sRGB":
|
||||
self.log.info("tx: converting sRGB -> linear")
|
||||
args.extend(["--colorconvert", "sRGB", "Raw"])
|
||||
else:
|
||||
self.log.info("tx: texture's colorspace "
|
||||
"is already linear")
|
||||
else:
|
||||
self.log.warning("tx: cannot guess the colorspace, "
|
||||
"color conversion won't be "
|
||||
"available!")
|
||||
|
||||
args.append("maketx")
|
||||
args.extend(args)
|
||||
|
||||
texture_hash = source_hash(source, *args)
|
||||
|
||||
# Exclude these additional arguments from the hashing because
|
||||
# it is the hash itself
|
||||
args.extend([
|
||||
"--sattrib",
|
||||
"sourceHash",
|
||||
texture_hash
|
||||
])
|
||||
|
||||
# Ensure folder exists
|
||||
converted = os.path.join(staging_dir, "resources", fname + ".tx")
|
||||
if not os.path.exists(os.path.dirname(converted)):
|
||||
os.makedirs(os.path.dirname(converted))
|
||||
|
||||
self.log.info("Generating .tx file for %s .." % source)
|
||||
|
||||
subprocess_args = [
|
||||
maketx_path,
|
||||
|
|
@ -186,18 +255,27 @@ class MakeTX(TextureProcessor):
|
|||
|
||||
self.log.debug(" ".join(subprocess_args))
|
||||
try:
|
||||
out = run_subprocess(subprocess_args)
|
||||
run_subprocess(subprocess_args)
|
||||
except Exception:
|
||||
self.log.error("Texture maketx conversion failed",
|
||||
exc_info=True)
|
||||
raise
|
||||
|
||||
return out
|
||||
return converted, COPY, texture_hash, render_colorspace
|
||||
|
||||
@staticmethod
|
||||
def get_extension():
|
||||
return ".tx"
|
||||
|
||||
@staticmethod
|
||||
def _has_arnold():
|
||||
"""Return whether the arnold package is available and importable."""
|
||||
try:
|
||||
import arnold # noqa: F401
|
||||
return True
|
||||
except (ImportError, ModuleNotFoundError):
|
||||
return False
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def no_workspace_dir():
|
||||
|
|
@ -565,7 +643,7 @@ class ExtractLook(publish.Extractor):
|
|||
basename, ext = os.path.splitext(os.path.basename(filepath))
|
||||
|
||||
# Get extension from the last processor
|
||||
for processors in reversed(processors):
|
||||
for processor in reversed(processors):
|
||||
ext = processor.get_extension()
|
||||
self.log.debug("Processor {} defined extension: "
|
||||
"{}".format(processor, ext))
|
||||
|
|
@ -620,7 +698,6 @@ class ExtractLook(publish.Extractor):
|
|||
Returns:
|
||||
tuple: (filepath, copy_mode, texture_hash, result_colorspace)
|
||||
"""
|
||||
fname, ext = os.path.splitext(os.path.basename(filepath))
|
||||
|
||||
# Note: The texture hash is only reliable if we include any potential
|
||||
# conversion arguments provide to e.g. `maketx`
|
||||
|
|
@ -629,104 +706,28 @@ class ExtractLook(publish.Extractor):
|
|||
|
||||
if len(processors) > 1:
|
||||
raise KnownPublishError(
|
||||
"More than one texture processor not supported"
|
||||
"More than one texture processor not supported. "
|
||||
"Current processors enabled: {}".format(processors)
|
||||
)
|
||||
|
||||
# TODO: Make all processors take the same arguments
|
||||
for processor in processors:
|
||||
if processor is MakeTX:
|
||||
processed_path = processor().process(filepath,
|
||||
converted,
|
||||
"--sattrib",
|
||||
"sourceHash",
|
||||
escape_space(texture_hash), # noqa
|
||||
colorconvert,
|
||||
color_config,
|
||||
)
|
||||
self.log.info("Generating texture file for %s .." % filepath) # noqa
|
||||
self.log.info(converted)
|
||||
if processed_path:
|
||||
return processed_path, COPY, texture_hash
|
||||
else:
|
||||
self.log.info("maketx has returned nothing")
|
||||
elif processor is MakeRSTexBin:
|
||||
processed_path = processor().process(filepath)
|
||||
self.log.info("Generating texture file for %s .." % filepath) # noqa
|
||||
if processed_path:
|
||||
return processed_path, COPY, texture_hash
|
||||
else:
|
||||
self.log.info("redshift texture converter has returned nothing") # noqa
|
||||
self.log.debug("Processing texture {} with processor {}".format(
|
||||
filepath, processor
|
||||
))
|
||||
|
||||
# TODO: continue this refactoring to processor
|
||||
if do_maketx and ext != ".tx":
|
||||
# Define .tx filepath in staging if source file is not .tx
|
||||
converted = os.path.join(staging_dir, "resources", fname + ".tx")
|
||||
processed_result = processor.process(filepath,
|
||||
colorspace,
|
||||
color_management)
|
||||
if not processed_result:
|
||||
raise RuntimeError("Texture Processor {} returned "
|
||||
"no result.".format(processor))
|
||||
|
||||
if color_management["enabled"]:
|
||||
config_path = color_management["config"]
|
||||
if not os.path.exists(config_path):
|
||||
raise RuntimeError("OCIO config not found at: "
|
||||
"{}".format(config_path))
|
||||
processed_path, processed_texture_hash = processed_result
|
||||
self.log.info("Generated processed "
|
||||
"texture: {}".format(processed_path))
|
||||
|
||||
render_colorspace = color_management["rendering_space"]
|
||||
|
||||
self.log.info("tx: converting colorspace {0} "
|
||||
"-> {1}".format(colorspace, render_colorspace))
|
||||
args.extend(["--colorconvert", colorspace, render_colorspace])
|
||||
args.extend(["--colorconfig", config_path])
|
||||
|
||||
else:
|
||||
# We can't rely on the colorspace attribute when not
|
||||
# in color managed mode because the collected color space
|
||||
# is the color space attribute of the file node which can be
|
||||
# any string whatsoever but only appears disabled in Attribute
|
||||
# Editor. We assume we're always converting to linear/Raw if
|
||||
# the source file is assumed to be sRGB.
|
||||
render_colorspace = "linear"
|
||||
if _has_arnold():
|
||||
img_info = image_info(filepath)
|
||||
color_space = guess_colorspace(img_info)
|
||||
if color_space.lower() == "sRGB":
|
||||
self.log.info("tx: converting sRGB -> linear")
|
||||
args.extend(["--colorconvert", "sRGB", "Raw"])
|
||||
else:
|
||||
self.log.info("tx: texture's colorspace "
|
||||
"is already linear")
|
||||
else:
|
||||
self.log.warning("tx: cannot guess the colorspace, "
|
||||
"color conversion won't be available!")
|
||||
|
||||
hash_args.append("maketx")
|
||||
hash_args.extend(args)
|
||||
|
||||
texture_hash = source_hash(filepath, *args)
|
||||
|
||||
if not force_copy:
|
||||
existing = self._get_existing_hashed_texture(filepath)
|
||||
if existing:
|
||||
return existing
|
||||
|
||||
# Exclude these additional arguments from the hashing because
|
||||
# it is the hash itself
|
||||
args.extend([
|
||||
"--sattrib",
|
||||
"sourceHash",
|
||||
texture_hash
|
||||
])
|
||||
|
||||
# Ensure folder exists
|
||||
if not os.path.exists(os.path.dirname(converted)):
|
||||
os.makedirs(os.path.dirname(converted))
|
||||
|
||||
self.log.info("Generating .tx file for %s .." % filepath)
|
||||
maketx(
|
||||
filepath,
|
||||
converted,
|
||||
args,
|
||||
self.log
|
||||
)
|
||||
|
||||
return converted, COPY, texture_hash, render_colorspace
|
||||
return processed_path, COPY, processed_texture_hash
|
||||
|
||||
# No special treatment for this file
|
||||
texture_hash = source_hash(filepath)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue