mirror of
https://github.com/blw1138/Zordon.git
synced 2025-12-19 17:58:12 +00:00
163 lines
5.7 KiB
Python
163 lines
5.7 KiB
Python
import logging
|
|
import os
|
|
import platform
|
|
import subprocess
|
|
|
|
logger = logging.getLogger()
|
|
SUBPROCESS_TIMEOUT = 5
|
|
|
|
|
|
class BaseRenderEngine(object):
|
|
"""Base class for render engines. This class provides common functionality and structure for various rendering
|
|
engines. Create subclasses and override the methods marked below to add additional renderers
|
|
|
|
Attributes:
|
|
install_paths (list): A list of default installation paths where the render engine
|
|
might be found. This list can be populated with common paths to help locate the
|
|
executable on different operating systems or environments.
|
|
"""
|
|
|
|
install_paths = []
|
|
|
|
# --------------------------------------------
|
|
# Required Overrides for Subclasses:
|
|
# --------------------------------------------
|
|
|
|
def __init__(self, custom_path=None):
|
|
self.custom_renderer_path = custom_path
|
|
if not self.renderer_path() or not os.path.exists(self.renderer_path()):
|
|
raise FileNotFoundError(f"Cannot find path to renderer for {self.name()} instance: {self.renderer_path()}")
|
|
|
|
if not os.access(self.renderer_path(), os.X_OK):
|
|
logger.warning(f"Path is not executable. Setting permissions to 755 for {self.renderer_path()}")
|
|
os.chmod(self.renderer_path(), 0o755)
|
|
|
|
def version(self):
|
|
"""Return the version number as a string.
|
|
|
|
Returns:
|
|
str: Version number.
|
|
|
|
Raises:
|
|
NotImplementedError: If not overridden.
|
|
"""
|
|
raise NotImplementedError(f"version not implemented for {self.__class__.__name__}")
|
|
|
|
def get_project_info(self, project_path, timeout=10):
|
|
"""Extracts detailed project information from the given project path.
|
|
|
|
Args:
|
|
project_path (str): The path to the project file.
|
|
timeout (int, optional): The maximum time (in seconds) to wait for the operation. Default is 10 seconds.
|
|
|
|
Returns:
|
|
dict: A dictionary containing project information (subclasses should define the structure).
|
|
|
|
Raises:
|
|
NotImplementedError: If the method is not overridden in a subclass.
|
|
"""
|
|
raise NotImplementedError(f"get_project_info not implemented for {self.__class__.__name__}")
|
|
|
|
@classmethod
|
|
def get_output_formats(cls):
|
|
"""Returns a list of available output formats supported by the renderer.
|
|
|
|
Returns:
|
|
list[str]: A list of strings representing the available output formats.
|
|
"""
|
|
raise NotImplementedError(f"get_output_formats not implemented for {cls.__name__}")
|
|
|
|
@staticmethod
|
|
def worker_class(): # override when subclassing to link worker class
|
|
raise NotImplementedError("Worker class not implemented")
|
|
|
|
# --------------------------------------------
|
|
# Optional Overrides for Subclasses:
|
|
# --------------------------------------------
|
|
|
|
def supported_extensions(self):
|
|
"""
|
|
Returns:
|
|
list[str]: list of supported extensions
|
|
"""
|
|
return []
|
|
|
|
def get_help(self):
|
|
"""Retrieves the help documentation for the renderer.
|
|
|
|
This method runs the renderer's help command (default: '-h') and captures the output.
|
|
Override this method if the renderer uses a different help flag.
|
|
|
|
Returns:
|
|
str: The help documentation as a string.
|
|
|
|
Raises:
|
|
FileNotFoundError: If the renderer path is not found.
|
|
"""
|
|
path = self.renderer_path()
|
|
if not path:
|
|
raise FileNotFoundError("renderer path not found")
|
|
creationflags = subprocess.CREATE_NO_WINDOW if platform.system() == 'Windows' else 0
|
|
help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT,
|
|
timeout=SUBPROCESS_TIMEOUT, creationflags=creationflags).decode('utf-8')
|
|
return help_doc
|
|
|
|
def system_info(self):
|
|
"""Return additional information about the system specfic to the engine (configured GPUs, render engines, etc)
|
|
|
|
Returns:
|
|
dict: A dictionary with engine-specific system information
|
|
"""
|
|
return {}
|
|
|
|
def perform_presubmission_tasks(self, project_path):
|
|
"""Perform any pre-submission tasks on a project file before uploading it to a server (pack textures, etc.)
|
|
|
|
Override this method to:
|
|
1. Copy the project file to a temporary location (DO NOT MODIFY ORIGINAL PATH).
|
|
2. Perform additional modifications or tasks.
|
|
3. Return the path to the modified project file.
|
|
|
|
Args:
|
|
project_path (str): The original project file path.
|
|
|
|
Returns:
|
|
str: The path to the modified project file.
|
|
"""
|
|
return project_path
|
|
|
|
def get_arguments(self):
|
|
pass
|
|
|
|
@staticmethod
|
|
def downloader(): # override when subclassing if using a downloader class
|
|
return None
|
|
|
|
@staticmethod
|
|
def ui_options(system_info): # override to return options for ui
|
|
return {}
|
|
|
|
# --------------------------------------------
|
|
# Do Not Override These Methods:
|
|
# --------------------------------------------
|
|
|
|
def renderer_path(self):
|
|
return self.custom_renderer_path or self.default_renderer_path()
|
|
|
|
@classmethod
|
|
def name(cls):
|
|
return str(cls.__name__).lower()
|
|
|
|
@classmethod
|
|
def default_renderer_path(cls):
|
|
path = None
|
|
try: # Linux and macOS
|
|
path = subprocess.check_output(['which', cls.name()], timeout=SUBPROCESS_TIMEOUT).decode('utf-8').strip()
|
|
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
for p in cls.install_paths:
|
|
if os.path.exists(p):
|
|
path = p
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
return path
|