Files
blender-portable-repo/scripts/addons/Substance3DInBlender/__init__.py
T
2026-03-17 14:30:01 -06:00

404 lines
14 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: __init__.py
# brief: Addon registration
# author Adobe - 3D & Immersive
# copyright 2023 Adobe Inc. All rights reserved.
bl_info = {
"name": "Adobe Substance 3D add-on for Blender",
"author": "Adobe Inc.",
"location": "Node Editor Toolbar -- Shift-Ctrl-U",
"version": (2, 1, 1),
"blender": (2, 90, 0),
"description": "Adobe Substance 3D add-on for Blender",
'tracker_url': "https://discord.gg/substance3d",
"category": "Node"
}
try:
import traceback
import bpy
from bpy.utils import register_class, unregister_class
from .persistance import SUBSTANCE_Persistance
from .api import SUBSTANCE_Api
from .utils import SUBSTANCE_Utils
from .thread_ops import SUBSTANCE_Threads
from .callbacks.render import Server_POST_Render
from .callbacks.link import Server_POST_Link
from .common import Code_Response, UI_SPACES, ADDON_PACKAGE, SHORTCUT_CLASS_NAME
from .ui.presets import SUBSTANCE_MT_PresetOptions
from .ui.shortcut import SubstanceShortcutMenuFactory
from .ui.sbsar import (
SubstanceMainPanelFactory,
SubstanceGraphPanelFactory,
SubstancePreviewFactory,
SubstanceOutputsPanelFactory,
SubstanceInputsPanelFactory,
SUBSTANCE_UL_SbsarList
)
from .preferences import SUBSTANCE_AddonPreferences
from .ops.common import SUBSTANCE_OT_Message, SUBSTANCE_OT_Version
from .ops.material import SUBSTANCE_OT_SetMaterial
from .ops.toolkit import (
SUBSTANCE_OT_InstallTools,
SUBSTANCE_OT_UpdateTools,
SUBSTANCE_OT_UninstallTools,
SUBSTANCE_OT_OpenTools,
SUBSTANCE_OT_ResetTools
)
from .ops.web import (
SUBSTANCE_OT_GoToWebsite,
SUBSTANCE_OT_GetTools,
SUBSTANCE_OT_GoToShare,
SUBSTANCE_OT_GoToSource,
SUBSTANCE_OT_GoToDocs,
SUBSTANCE_OT_GoToForums,
SUBSTANCE_OT_GoToDiscord
)
from .ops.inputs import (
SUBSTANCE_OT_RandomizeSeed,
SUBSTANCE_OT_InputGroupsCollapse,
SUBSTANCE_OT_InputGroupsExpand
)
from .ops.presets import (
SUBSTANCE_OT_AddPreset,
SUBSTANCE_OT_ImportPreset,
SUBSTANCE_OT_ExportPreset,
SUBSTANCE_OT_ExportAll,
SUBSTANCE_OT_DeletePreset,
SUBSTANCE_OT_DeletePresetModal
)
from .ops.sbsar import (
SUBSTANCE_OT_LoadSBSAR,
SUBSTANCE_OT_ApplySBSAR,
SUBSTANCE_OT_RemoveSBSAR,
SUBSTANCE_OT_ReloadSBSAR,
SUBSTANCE_OT_DuplicateSBSAR
)
from .ops.shader import (
SUBSTANCE_OT_ResetShaderPreset,
SUBSTANCE_OT_LoadShaderPresets,
SUBSTANCE_OT_RemoveShaderPresets,
SUBSTANCE_OT_SaveShaderPresets
)
from .ops.sync import (
SUBSTANCE_OT_SyncInitTools,
SUBSTANCE_OT_SyncLoadSBSAR
)
from .props.shortcuts import SUBSTANCE_PG_Shortcuts
from .props.common import SUBSTANCE_PG_Tiling, SUBSTANCE_PG_Resolution, SUBSTANCE_PG_SbsarPhysicalSize
from .props.sbsar_graph import SUBSTANCE_PG_SbsarGraph, SUBSTANCE_PG_SbsarMaterial, SUBSTANCE_PG_SbsarTiling
from .props.sbsar_input import SUBSTANCE_PG_SbsarInputGroup, SUBSTANCE_PG_SbsarInput
from .props.sbsar_output import SUBSTANCE_PG_SbsarOutput, SUBSTANCE_PG_SbsarOutputChannelUse
from .props.sbsar_preset import SUBSTANCE_PG_SbsarPreset
from .props.sbsar import SUBSTANCE_PG_Sbsar
from .props.shader import SUBSTANCE_PG_ShaderPreset, SUBSTANCE_PG_ShaderInput, SUBSTANCE_PG_ShaderOutput
SHORTCUT_KEYMAPS = []
FACTORY_CLASSES = []
DEFAULT_CLASSES = [
# /props/common
SUBSTANCE_PG_Tiling,
SUBSTANCE_PG_Resolution,
# /props/sbsar
SUBSTANCE_PG_SbsarPhysicalSize,
SUBSTANCE_PG_SbsarInputGroup,
SUBSTANCE_PG_SbsarInput,
SUBSTANCE_PG_SbsarOutputChannelUse,
SUBSTANCE_PG_SbsarOutput,
SUBSTANCE_PG_SbsarPreset,
SUBSTANCE_PG_SbsarMaterial,
SUBSTANCE_PG_SbsarTiling,
SUBSTANCE_PG_SbsarGraph,
SUBSTANCE_PG_Sbsar,
# /props/shader
SUBSTANCE_PG_ShaderOutput,
SUBSTANCE_PG_ShaderInput,
SUBSTANCE_PG_ShaderPreset,
# /props/shortcuts
SUBSTANCE_PG_Shortcuts,
# /preferences
SUBSTANCE_AddonPreferences,
# /ops/common
SUBSTANCE_OT_Version,
SUBSTANCE_OT_Message,
# /ops/toolkit
SUBSTANCE_OT_InstallTools,
SUBSTANCE_OT_UpdateTools,
SUBSTANCE_OT_UninstallTools,
SUBSTANCE_OT_OpenTools,
SUBSTANCE_OT_ResetTools,
# /ops/web
SUBSTANCE_OT_GoToWebsite,
SUBSTANCE_OT_GetTools,
SUBSTANCE_OT_GoToShare,
SUBSTANCE_OT_GoToSource,
SUBSTANCE_OT_GoToDocs,
SUBSTANCE_OT_GoToForums,
SUBSTANCE_OT_GoToDiscord,
# /ops/inputs
SUBSTANCE_OT_RandomizeSeed,
SUBSTANCE_OT_InputGroupsCollapse,
SUBSTANCE_OT_InputGroupsExpand,
# /ops/presets
SUBSTANCE_OT_AddPreset,
SUBSTANCE_OT_ImportPreset,
SUBSTANCE_OT_ExportPreset,
SUBSTANCE_OT_ExportAll,
SUBSTANCE_OT_DeletePreset,
SUBSTANCE_OT_DeletePresetModal,
# /ops/sbsar
SUBSTANCE_OT_LoadSBSAR,
SUBSTANCE_OT_ApplySBSAR,
SUBSTANCE_OT_RemoveSBSAR,
SUBSTANCE_OT_ReloadSBSAR,
SUBSTANCE_OT_DuplicateSBSAR,
# /ops/shader
SUBSTANCE_OT_LoadShaderPresets,
SUBSTANCE_OT_RemoveShaderPresets,
SUBSTANCE_OT_SaveShaderPresets,
SUBSTANCE_OT_ResetShaderPreset,
# /ops/material
SUBSTANCE_OT_SetMaterial,
# /ops/sync
SUBSTANCE_OT_SyncInitTools,
SUBSTANCE_OT_SyncLoadSBSAR,
# /ui/presets
SUBSTANCE_MT_PresetOptions,
# /ui/sbsar
SUBSTANCE_UL_SbsarList
]
# Callback for SBSAR
def sbsar_index_changed(self, context):
SUBSTANCE_Utils.toggle_redraw(context)
# Preview Update FIX
def sbsar_redraw_changed(self, context):
try:
context.area.tag_redraw()
except Exception:
pass
post_render = Server_POST_Render()
post_link = Server_POST_Link()
def register():
# Add Panels
if len(FACTORY_CLASSES) == 0:
for _space in UI_SPACES:
# Add Substance List Panel
_cls = SubstanceMainPanelFactory(_space[1])
FACTORY_CLASSES.append(_cls)
_cls = SubstancePreviewFactory(_space[1])
FACTORY_CLASSES.append(_cls)
_cls = SubstanceGraphPanelFactory(_space[1])
FACTORY_CLASSES.append(_cls)
_cls = SubstanceOutputsPanelFactory(_space[1])
FACTORY_CLASSES.append(_cls)
_cls = SubstanceInputsPanelFactory(_space[1])
FACTORY_CLASSES.append(_cls)
_menu_cls = SubstanceShortcutMenuFactory(_space[1])
FACTORY_CLASSES.append(_menu_cls)
# Register blender classes
for _cls in DEFAULT_CLASSES:
register_class(_cls)
for _cls in FACTORY_CLASSES:
register_class(_cls)
# Addon Preferences
_addon_prefs = bpy.context.preferences.addons[ADDON_PACKAGE].preferences
# Shortcuts
_shortcuts = _addon_prefs.shortcuts
wm = bpy.context.window_manager
_kc = wm.keyconfigs.addon
for _space in UI_SPACES:
if _kc:
_km = wm.keyconfigs.addon.keymaps.new(name=_space[0], space_type=_space[1])
_kmi = _km.keymap_items.new(
'wm.call_menu',
_shortcuts.menu_key,
'PRESS',
ctrl=_shortcuts.menu_ctrl,
shift=_shortcuts.menu_shift,
alt=_shortcuts.menu_alt
)
_kmi.properties.name = SHORTCUT_CLASS_NAME.format(_space[1])
SHORTCUT_KEYMAPS.append((_km, _kmi))
_kmi = _km.keymap_items.new(
SUBSTANCE_OT_LoadSBSAR.bl_idname,
_shortcuts.load_key,
'PRESS',
ctrl=_shortcuts.load_ctrl,
shift=_shortcuts.load_shift,
alt=_shortcuts.load_alt
)
SHORTCUT_KEYMAPS.append((_km, _kmi))
_kmi = _km.keymap_items.new(
SUBSTANCE_OT_ApplySBSAR.bl_idname,
_shortcuts.apply_key,
'PRESS',
ctrl=_shortcuts.apply_ctrl,
shift=_shortcuts.apply_shift,
alt=_shortcuts.apply_alt
)
SHORTCUT_KEYMAPS.append((_km, _kmi))
# Create scene SBSAR variables
bpy.types.Scene.loaded_sbsars = bpy.props.CollectionProperty(type=SUBSTANCE_PG_Sbsar)
bpy.types.Scene.sbsar_index = bpy.props.IntProperty(
name='sbsar_index',
default=0,
options={'HIDDEN'},
update=sbsar_index_changed
)
# Create a dumb variable to fix the Preview Update
bpy.types.Scene.sbsar_redraw = bpy.props.IntProperty(
name='sbsar_redraw',
default=0,
options={'HIDDEN'},
update=sbsar_redraw_changed
)
# Init icons
SUBSTANCE_Utils.init_icons()
# Shader Presets
_result = SUBSTANCE_Api.shader_initialize(_addon_prefs)
if _result[0] != Code_Response.success:
SUBSTANCE_Utils.log_data("ERROR", "[{}] Shader presets cannot be initialized...".format(_result))
return
SUBSTANCE_Utils.log_data("INFO", "Shader Presets initialized...")
# 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)
# Initialize blender handlers
bpy.app.handlers.load_post.append(SUBSTANCE_Persistance.sbs_load_post_handler)
bpy.app.handlers.load_pre.append(SUBSTANCE_Persistance.sbs_load_pre_handler)
bpy.app.handlers.save_pre.append(SUBSTANCE_Persistance.sbs_save_pre_handler)
bpy.app.handlers.save_post.append(SUBSTANCE_Persistance.sbs_save_post_handler)
bpy.app.handlers.undo_post.append(SUBSTANCE_Persistance.sbs_undo_post_handler)
bpy.app.handlers.depsgraph_update_post.append(SUBSTANCE_Persistance.sbs_depsgraph_update_post)
# Initialize SUBSTANCE_Api listeners
SUBSTANCE_Api.listeners_add("post", post_render)
SUBSTANCE_Api.listeners_add("post", post_link)
# Initialize SRE if enabled
if _addon_prefs.auto_start_sre:
_result = SUBSTANCE_Api.initialize()
if _result[0] != Code_Response.success:
SUBSTANCE_Utils.log_data("ERROR", "[{}] The SRE cannot initialize...".format(_result))
def unregister():
# Remove shortcuts
for _km, _kmi in SHORTCUT_KEYMAPS:
_km.keymap_items.remove(_kmi)
SHORTCUT_KEYMAPS.clear()
# Remove sbsar dynamic classes
for _scene in bpy.data.scenes:
for _item in _scene.loaded_sbsars:
SUBSTANCE_Api.sbsar_unregister(_item.uuid)
_scene.loaded_sbsars.clear()
# Shutdown SUBSTANCE_Api
SUBSTANCE_Api.listeners_remove("post", post_render)
SUBSTANCE_Api.listeners_remove("post", post_link)
SUBSTANCE_Api.shutdown()
# Remove blender handlers
for _func in bpy.app.handlers.load_pre[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_load_pre_handler.__name__:
bpy.app.handlers.load_pre.remove(_func)
for _func in bpy.app.handlers.load_post[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_load_post_handler.__name__:
bpy.app.handlers.load_post.remove(_func)
for _func in bpy.app.handlers.save_pre[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_save_pre_handler.__name__:
bpy.app.handlers.save_pre.remove(_func)
for _func in bpy.app.handlers.save_post[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_save_post_handler.__name__:
bpy.app.handlers.save_post.remove(_func)
for _func in bpy.app.handlers.undo_post[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_undo_post_handler.__name__:
bpy.app.handlers.undo_post.remove(_func)
for _func in bpy.app.handlers.depsgraph_update_post[:]:
if _func.__name__ == SUBSTANCE_Persistance.sbs_depsgraph_update_post.__name__:
bpy.app.handlers.depsgraph_update_post.remove(_func)
# Remove main thread listener
if bpy.app.timers.is_registered(SUBSTANCE_Threads.exec_queued_function):
bpy.app.timers.unregister(SUBSTANCE_Threads.exec_queued_function)
# Cleanup Shader Presets list
bpy.ops.substance.save_shader_presets()
bpy.ops.substance.remove_shader_presets()
# Delete scene SBSAR variables
del bpy.types.Scene.loaded_sbsars
del bpy.types.Scene.sbsar_index
del bpy.types.Scene.sbsar_redraw
# Unregister blender classes
for _cls in reversed(DEFAULT_CLASSES):
unregister_class(_cls)
for _cls in reversed(FACTORY_CLASSES):
unregister_class(_cls)
if __name__ == "__main__":
register()
except Exception:
print(traceback.format_exc())