270 lines
12 KiB
Python
270 lines
12 KiB
Python
"""
|
|
Copyright (C) 2023 Adobe.
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
"""
|
|
|
|
# file: persistance.py
|
|
# brief: Persistance handlers for blender
|
|
# author Adobe - 3D & Immersive
|
|
# copyright 2023 Adobe Inc. All rights reserved.
|
|
|
|
|
|
import os
|
|
import shutil
|
|
import traceback
|
|
import bpy
|
|
from bpy.app.handlers import persistent
|
|
|
|
from .api import SUBSTANCE_Api
|
|
from .sbsar.sbsar import SBSAR
|
|
from .thread_ops import SUBSTANCE_Threads
|
|
from .utils import SUBSTANCE_Utils
|
|
from .material.manager import SUBSTANCE_MaterialManager
|
|
from .common import (
|
|
Code_SbsarOp,
|
|
Code_Response,
|
|
ADDON_PACKAGE
|
|
)
|
|
|
|
|
|
class SUBSTANCE_Persistance():
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_load_pre_handler(dummy):
|
|
pass
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_load_post_handler(dummy):
|
|
try:
|
|
# Add main thread listener
|
|
if not bpy.app.timers.is_registered(SUBSTANCE_Threads.exec_queued_function):
|
|
bpy.app.timers.register(SUBSTANCE_Threads.exec_queued_function)
|
|
|
|
# Get current scene
|
|
_scene = bpy.context.scene
|
|
if hasattr(_scene, "loaded_sbsars") and len(_scene.loaded_sbsars) > 0:
|
|
if not SUBSTANCE_Api.currently_running:
|
|
# Initialize SUBSTANCE_Api
|
|
_result = SUBSTANCE_Api.initialize()
|
|
if _result[0] != Code_Response.success:
|
|
SUBSTANCE_Utils.log_data("ERROR", "[{}] The SRE cannot initialize...".format(_result))
|
|
return
|
|
|
|
for _sbsar in _scene.loaded_sbsars:
|
|
try:
|
|
_graph_idx = int(_sbsar.graphs_list)
|
|
_graph = _sbsar.graphs[_graph_idx]
|
|
_preset_idx = int(_graph.presets_list)
|
|
_preset = _graph.presets[_preset_idx]
|
|
_filepath = bpy.path.abspath(_sbsar.filepath)
|
|
_filepath = os.path.abspath(_filepath)
|
|
_filepath = _filepath.replace("\\", "/")
|
|
|
|
if not os.path.exists(_filepath):
|
|
SUBSTANCE_Utils.log_data(
|
|
"ERROR",
|
|
"Substance file [{}] doesn't exist".format(_sbsar.filepath))
|
|
continue
|
|
|
|
_data = {
|
|
"filepath": _filepath,
|
|
"name": _sbsar.name,
|
|
"uuid": _sbsar.uuid,
|
|
"graph_idx": _graph_idx,
|
|
"preset": _preset.value
|
|
}
|
|
|
|
# Load the sbsar to the SRE
|
|
_result = SUBSTANCE_Api.sbsar_load(_data, operation=Code_SbsarOp.reload)
|
|
if _result[0] != Code_Response.success:
|
|
SUBSTANCE_Utils.log_data(
|
|
"ERROR",
|
|
"Substance file [{}] located at [{}] could not be loaded".format(
|
|
_sbsar.filename, _sbsar.filepath),
|
|
display=True)
|
|
continue
|
|
if _result[1]["result"] != Code_Response.success.value:
|
|
SUBSTANCE_Utils.log_data(
|
|
"ERROR",
|
|
"An error ocurred while loading Substance file [{}]. Failed with error [{}]".format(
|
|
_sbsar.filepath, _result[1]["result"]),
|
|
display=True)
|
|
continue
|
|
|
|
_addon_prefs = bpy.context.preferences.addons[ADDON_PACKAGE].preferences
|
|
_new_sbsar = SBSAR(_sbsar.name, _sbsar.filename, _result[1]["data"], _addon_prefs)
|
|
|
|
for _graph_obj in _new_sbsar.graphs:
|
|
_sbsar.graphs[int(_graph_obj.index)].uid = _graph_obj.uid
|
|
_presets = []
|
|
_preset_list = _sbsar.graphs[int(_graph_obj.index)].presets
|
|
for _item in _preset_list:
|
|
_obj = {
|
|
"index": int(_item.index),
|
|
"label": _item.label,
|
|
"value": _item.value,
|
|
"icon": _item.icon,
|
|
"embedded": _item.embedded
|
|
}
|
|
_presets.append(_obj)
|
|
_graph_obj.reset_presets(_presets)
|
|
SUBSTANCE_Api.sbsar_register(_new_sbsar)
|
|
except Exception:
|
|
# TODO: Change the sbsar icon to error if load fails
|
|
print("change sbsar icon to error")
|
|
|
|
SUBSTANCE_Utils.log_data("INFO", "Scene Substances loaded correctly", display=True)
|
|
except Exception:
|
|
SUBSTANCE_Utils.log_data("ERROR", "Exception - Substance load failed")
|
|
SUBSTANCE_Utils.log_traceback(traceback.format_exc())
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_save_pre_handler(dummy):
|
|
try:
|
|
SUBSTANCE_Api.temp_sbs_files.clear()
|
|
SUBSTANCE_Api.temp_tx_files.clear()
|
|
_addons_prefs = bpy.context.preferences.addons[ADDON_PACKAGE].preferences
|
|
_relative_tx_path = _addons_prefs.path_relative_tx
|
|
_scene = bpy.context.scene
|
|
|
|
for _sbsar in _scene.loaded_sbsars:
|
|
if not _sbsar.load_success:
|
|
continue
|
|
|
|
if _addons_prefs.path_relative_sbsar_enabled:
|
|
_original_filepath = bpy.path.abspath(_sbsar.filepath)
|
|
_original_filepath = os.path.abspath(_original_filepath)
|
|
_original_filepath = _original_filepath.replace("\\", "/")
|
|
_sbsar_path = _addons_prefs.path_relative_sbsar
|
|
_sbsar_path = _sbsar_path[2:] if _sbsar_path.startswith("//") else _sbsar_path
|
|
_sbsar_path = _sbsar_path[:-1] if _sbsar_path.endswith("/") else _sbsar_path
|
|
_sbsar.filepath = "//{}/{}".format(_sbsar_path, _sbsar.filename)
|
|
SUBSTANCE_Api.temp_sbs_files.append({
|
|
"sbsar_path": _sbsar_path,
|
|
"original_path": _original_filepath,
|
|
"filename": _sbsar.filename
|
|
})
|
|
|
|
for _graph in _sbsar.graphs:
|
|
if SUBSTANCE_MaterialManager.get_existing_material(_graph.material.name) is None:
|
|
continue
|
|
|
|
for _output in _graph.outputs:
|
|
if _output.filename == "":
|
|
continue
|
|
_original_filepath = bpy.path.abspath(_output.filepath)
|
|
_original_filepath = os.path.abspath(_original_filepath)
|
|
_original_filepath = _original_filepath.replace("\\", "/")
|
|
_mat_path = _relative_tx_path.replace("$matname", _graph.material.name)
|
|
_mat_path = _mat_path[2:] if _mat_path.startswith("//") else _mat_path
|
|
_mat_path = _mat_path[:-1] if _mat_path.endswith("/") else _mat_path
|
|
_output.filepath = "//{}/{}".format(_mat_path, _output.filename)
|
|
|
|
_item = {
|
|
"img": "{}_{}".format(_graph.material.name, _output.name),
|
|
"mat_path": _mat_path,
|
|
"filepath": _original_filepath,
|
|
"filename": _output.filename,
|
|
"new_path": _output.filepath,
|
|
"mat_name": _graph.material.name
|
|
}
|
|
SUBSTANCE_Api.temp_tx_files.append(_item)
|
|
if _item["img"] in bpy.data.images:
|
|
bpy.data.images[_item["img"]].filepath = _item["new_path"]
|
|
|
|
except Exception:
|
|
SUBSTANCE_Utils.log_data("ERROR", "Exception - Susbtance pre save data error")
|
|
SUBSTANCE_Utils.log_traceback(traceback.format_exc())
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_save_post_handler(dummy):
|
|
try:
|
|
_filepath = bpy.data.filepath.replace("\\", "/")
|
|
_filedir = os.path.dirname(_filepath)
|
|
|
|
for _item in SUBSTANCE_Api.temp_sbs_files:
|
|
_sbs_dir = "{}/{}".format(_filedir, _item["sbsar_path"])
|
|
if not os.path.exists(_sbs_dir):
|
|
os.makedirs(_sbs_dir)
|
|
_src = _item["original_path"]
|
|
_dst = "{}/{}".format(_sbs_dir, _item["filename"])
|
|
if _src != _dst and os.path.exists(_src) and os.path.isfile(_src):
|
|
shutil.copyfile(_src, _dst)
|
|
SUBSTANCE_Utils.log_data(
|
|
"INFO",
|
|
"Susbtance [{}] moved to relative path".format(_item["filename"]))
|
|
|
|
for _item in SUBSTANCE_Api.temp_tx_files:
|
|
SUBSTANCE_Utils.log_data("INFO", "Moved to Tx relative path [{}]".format(_item["img"]))
|
|
_tx_dir = "{}/{}".format(_filedir, _item["mat_path"])
|
|
if not os.path.exists(_tx_dir):
|
|
os.makedirs(_tx_dir)
|
|
_new_filepath = os.path.join(_tx_dir, _item["filename"]).replace("\\", "/")
|
|
|
|
try:
|
|
if (_item["filepath"] != _new_filepath and
|
|
os.path.exists(_item["filepath"]) and
|
|
os.path.isfile(_item["filepath"])):
|
|
shutil.move(_item["filepath"], _new_filepath)
|
|
except Exception:
|
|
SUBSTANCE_Utils.log_data(
|
|
"ERROR",
|
|
"Error while moving [{}] file to relative path".format(_item["filepath"]))
|
|
SUBSTANCE_Utils.log_traceback(traceback.format_exc())
|
|
|
|
if _item["img"] in bpy.data.images:
|
|
bpy.data.images[_item["img"]].reload()
|
|
|
|
SUBSTANCE_Api.temp_sbs_files.clear()
|
|
SUBSTANCE_Api.temp_tx_files.clear()
|
|
SUBSTANCE_Utils.log_data("INFO", "Susbtance textures saved")
|
|
except Exception:
|
|
SUBSTANCE_Utils.log_data("ERROR", "Exception - Susbtance post save data error")
|
|
SUBSTANCE_Utils.log_traceback(traceback.format_exc())
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_undo_post_handler(dummy):
|
|
pass
|
|
|
|
@staticmethod
|
|
@persistent
|
|
def sbs_depsgraph_update_post(dummy):
|
|
_addons_prefs = bpy.context.preferences.addons[ADDON_PACKAGE].preferences
|
|
if not _addons_prefs.auto_highlight_sbsar:
|
|
return
|
|
|
|
_selected_objects = bpy.context.selected_objects
|
|
if len(_selected_objects) == 0:
|
|
return
|
|
|
|
if SUBSTANCE_Api.last_selection == _selected_objects:
|
|
return
|
|
|
|
SUBSTANCE_Api.last_selection = _selected_objects
|
|
for _obj in _selected_objects:
|
|
if not hasattr(_obj.data, "materials"):
|
|
continue
|
|
|
|
for _idx, _key in enumerate(bpy.context.scene.loaded_sbsars):
|
|
for _graph in bpy.context.scene.loaded_sbsars[_idx].graphs:
|
|
if _graph.material.name in _obj.data.materials:
|
|
bpy.context.scene.loaded_sbsars[_idx].graphs_list = _graph.index
|
|
bpy.context.scene.sbsar_index = _idx
|
|
return
|