""" 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 . """ # 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())