diff --git a/__init__.py b/__init__.py index 0c5ec60..2c1cbaa 100644 --- a/__init__.py +++ b/__init__.py @@ -24,6 +24,7 @@ def load_post_handler(_dummy): module_names = ( "operators.core", "operators.material", + "operators.marmoset", "preferences", "ui" ) diff --git a/baker.py b/baker.py index a9947bc..0728618 100644 --- a/baker.py +++ b/baker.py @@ -37,13 +37,13 @@ class Baker(PropertyGroup): ('blender_workbench', "Workbench", "")) def __init__(self): - """Called when `bpy.ops.grab_doc.scene_setup` operator is ran. + """Called in `create_baker_panels()`. - This method is NOT called when created via `CollectionProperty`.""" + Class fails to instantiate when created via `CollectionProperty`.""" self.node_input = None self.node_output = None - # NOTE: For properties using constants as defaults + # Assign properties using constants as defaults self.__class__.suffix = StringProperty( description="The suffix of the exported bake map", name="Suffix", default=self.ID @@ -53,21 +53,19 @@ def __init__(self): items=self.SUPPORTED_ENGINES, update=self.__class__.apply_render_settings ) - self.__class__.suffix = StringProperty( - description="The suffix of the exported bake map", - name="Suffix", default=self.ID - ) self.__class__.enabled = BoolProperty( name="Export Enabled", default=self.MARMOSET_COMPATIBLE ) + # Assign "absolute" index if self.index == -1: gd = bpy.context.scene.gd self.index = self.get_unique_index(getattr(gd, self.ID)) - if self.index > 0: - self.node_name = self.get_node_name(self.NAME, self.index+1) - if not self.suffix[-1].isdigit(): - self.suffix = f"{self.suffix}_{self.index+1}" + if self.index == 0: + return + self.node_name = self.get_node_name(self.NAME, self.index+1) + if not self.suffix[-1].isdigit(): + self.suffix = f"{self.suffix}_{self.index+1}" @staticmethod def get_unique_index(collection: CollectionProperty) -> int: @@ -170,19 +168,18 @@ def draw(self, context: Context, layout: UILayout): col = layout.column() box = col.box() - box.label(text="Properties", icon="PROPERTIES") - row = box.row(align=True) - if len(self.SUPPORTED_ENGINES) < 2: - row.enabled = False - row.prop(self, 'engine') - + box.label(text="Properties", icon='PROPERTIES') self.draw_properties(context, box) box = col.box() - box.label(text="Settings", icon="SETTINGS") + box.label(text="Settings", icon='SETTINGS') col_set = box.column() gd = context.scene.gd if gd.engine == 'grabdoc': + row = col_set.row(align=True) + if len(self.SUPPORTED_ENGINES) < 2: + row.enabled = False + row.prop(self, 'engine') col_set.prop(self, 'reimport') col_set.prop(self, 'disable_filtering') prop = 'samples' @@ -678,27 +675,27 @@ def draw_properties(self, context: Context, layout: UILayout): col = layout.column(align=True) col.separator(factor=.5) col.scale_y = 1.1 - col.operator("grab_doc.quick_id_setup") + col.operator("grabdoc.quick_id_setup") row = col.row(align=True) row.scale_y = .9 row.label(text=" Remove:") row.operator( - "grab_doc.remove_mats_by_name", + "grabdoc.remove_mats_by_name", text='All' ).name = Global.RANDOM_ID_PREFIX col = layout.column(align=True) col.separator(factor=.5) col.scale_y = 1.1 - col.operator("grab_doc.quick_id_selected") + col.operator("grabdoc.quick_id_selected") row = col.row(align=True) row.scale_y = .9 row.label(text=" Remove:") - row.operator("grab_doc.remove_mats_by_name", + row.operator("grabdoc.remove_mats_by_name", text='All').name = Global.ID_PREFIX - row.operator("grab_doc.quick_remove_selected_mats", + row.operator("grabdoc.quick_remove_selected_mats", text='Selected') def update_method(self, context: Context): diff --git a/blender_manifest.toml b/blender_manifest.toml index 97d3441..bb513a7 100644 --- a/blender_manifest.toml +++ b/blender_manifest.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "GrabDoc" -version = "2.0.0" +version = "2.0.1" name = "GrabDoc" tagline = "A trim & tileable baker for Blender" maintainer = "Ethan Simon-Law " diff --git a/operators/core.py b/operators/core.py index bb10e76..cd8f86f 100644 --- a/operators/core.py +++ b/operators/core.py @@ -27,7 +27,7 @@ class GRABDOC_OT_load_reference(Operator): """Import a reference onto the background plane""" - bl_idname = "grab_doc.load_reference" + bl_idname = "grabdoc.load_reference" bl_label = "Load Reference" bl_options = {'REGISTER', 'UNDO'} @@ -46,7 +46,7 @@ def invoke(self, context: Context, _event: Event): class GRABDOC_OT_open_folder(Operator): """Opens up the File Explorer to the designated folder location""" - bl_idname = "grab_doc.open_folder" + bl_idname = "grabdoc.open_folder" bl_label = "Open Export Folder" bl_options = {'REGISTER', 'UNDO'} @@ -61,7 +61,7 @@ def execute(self, context: Context): class GRABDOC_OT_toggle_camera_view(Operator): """View or leave the GrabDoc camera view""" - bl_idname = "grab_doc.toggle_camera_view" + bl_idname = "grabdoc.toggle_camera_view" bl_label = "Toggle Camera View" def execute(self, context: Context): @@ -76,7 +76,7 @@ class GRABDOC_OT_scene_setup(Operator): Useful for rare cases where GrabDoc isn't compatible with an existing setup. Can also potentially fix console spam from UI elements""" - bl_idname = "grab_doc.scene_setup" + bl_idname = "grabdoc.scene_setup" bl_label = "Setup GrabDoc Scene" bl_options = {'REGISTER', 'INTERNAL'} @@ -99,7 +99,7 @@ def execute(self, context: Context): class GRABDOC_OT_scene_cleanup(Operator): """Remove all GrabDoc objects from the scene; keeps reimported textures""" - bl_idname = "grab_doc.scene_cleanup" + bl_idname = "grabdoc.scene_cleanup" bl_label = "Remove GrabDoc Scene" bl_options = {'REGISTER', 'INTERNAL'} @@ -114,7 +114,7 @@ def execute(self, context: Context): class GRABDOC_OT_baker_add(Operator): """Add a new baker of this type to the current scene""" - bl_idname = "grab_doc.baker_add" + bl_idname = "grabdoc.baker_add" bl_label = "Add Bake Map" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} @@ -130,7 +130,7 @@ def execute(self, context: Context): class GRABDOC_OT_baker_remove(Operator): """Remove the current baker from the current scene""" - bl_idname = "grab_doc.baker_remove" + bl_idname = "grabdoc.baker_remove" bl_label = "Remove Baker" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} @@ -152,17 +152,18 @@ def execute(self, context: Context): class GRABDOC_OT_baker_export(Operator, UILayout): """Bake and export all enabled bake maps""" - bl_idname = "grab_doc.baker_export" + bl_idname = "grabdoc.baker_export" bl_label = "Export Maps" bl_options = {'REGISTER', 'INTERNAL'} progress_factor = 0.0 + map_type = '' @classmethod def poll(cls, context: Context) -> bool: gd = context.scene.gd if gd.filepath == "//" and not bpy.data.filepath: - cls.poll_message_set("Relative export path but file not saved") + cls.poll_message_set("Relative export path set but file not saved") return False if gd.preview_state: cls.poll_message_set("Cannot run while in Map Preview") @@ -271,7 +272,7 @@ def execute(self, context: Context): context.window_manager.progress_end() if gd.use_pack_maps is True: - bpy.ops.grab_doc.baker_pack() + bpy.ops.grabdoc.baker_pack() return {'FINISHED'} @@ -279,7 +280,7 @@ class GRABDOC_OT_baker_export_single(Operator): """Render the selected bake map and preview it within Blender. Rendering a second time will overwrite the internal image""" - bl_idname = "grab_doc.baker_export_single" + bl_idname = "grabdoc.baker_export_single" bl_label = "" bl_options = {'REGISTER', 'INTERNAL'} @@ -366,7 +367,7 @@ def execute(self, context: Context): class GRABDOC_OT_baker_preview_exit(Operator): """Exit the current Map Preview""" - bl_idname = "grab_doc.baker_preview_exit" + bl_idname = "grabdoc.baker_preview_exit" bl_label = "Exit Map Preview" bl_options = {'REGISTER', 'INTERNAL'} @@ -414,7 +415,7 @@ def draw_callback_px(self, context: Context) -> None: class GRABDOC_OT_baker_preview(Operator): """Preview the selected bake map type""" - bl_idname = "grab_doc.baker_preview" + bl_idname = "grabdoc.baker_preview" bl_label = "" bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} @@ -542,7 +543,7 @@ def execute(self, context: Context): class GRABDOC_OT_baker_preview_export(Operator): """Export the currently previewed material""" - bl_idname = "grab_doc.baker_export_preview" + bl_idname = "grabdoc.baker_export_preview" bl_label = "Export Preview" bl_options = {'REGISTER'} @@ -552,7 +553,7 @@ class GRABDOC_OT_baker_preview_export(Operator): def poll(cls, context: Context) -> bool: gd = context.scene.gd if gd.filepath == "//" and not bpy.data.filepath: - cls.poll_message_set("Relative export path but file not saved") + cls.poll_message_set("Relative export path set but file not saved") return False return not GRABDOC_OT_baker_export_single.poll(context) @@ -590,7 +591,7 @@ def execute(self, context: Context): class GRABDOC_OT_baker_visibility(Operator): """Configure bake map UI visibility, will also disable baking""" - bl_idname = "grab_doc.baker_visibility" + bl_idname = "grabdoc.baker_visibility" bl_label = "Configure Baker Visibility" bl_options = {'REGISTER'} @@ -614,7 +615,7 @@ def draw(self, _context: Context): class GRABDOC_OT_baker_pack(Operator): """Merge previously exported bake maps into single packed texture""" - bl_idname = "grab_doc.baker_pack" + bl_idname = "grabdoc.baker_pack" bl_label = "Run Pack" bl_options = {'REGISTER'} diff --git a/operators/marmoset.py b/operators/marmoset.py index 0395ab9..92e001d 100644 --- a/operators/marmoset.py +++ b/operators/marmoset.py @@ -17,7 +17,7 @@ class GrabDoc_OT_send_to_marmo(Operator): """Export your models, open and bake the enabled maps in Marmoset Toolbag""" - bl_idname = "grab_doc.bake_marmoset" + bl_idname = "grabdoc.bake_marmoset" bl_label = "Open / Refresh in Marmoset" bl_options = {'REGISTER', 'INTERNAL'} diff --git a/operators/material.py b/operators/material.py index 95dcaaf..d53209e 100644 --- a/operators/material.py +++ b/operators/material.py @@ -10,7 +10,7 @@ class GRABDOC_OT_quick_id_setup(Operator): """Sets up materials on all objects within the cameras view frustrum""" - bl_idname = "grab_doc.quick_id_setup" + bl_idname = "grabdoc.quick_id_setup" bl_label = "Auto ID Full Scene" bl_options = {'REGISTER', 'UNDO'} @@ -69,7 +69,7 @@ def execute(self, _context: Context): class GRABDOC_OT_quick_id_selected(UseSelectedOnly, Operator): """Adds a new single material with a random color to the selected objects""" - bl_idname = "grab_doc.quick_id_selected" + bl_idname = "grabdoc.quick_id_selected" bl_label = "Add ID to Selected" bl_options = {'REGISTER', 'UNDO'} @@ -94,7 +94,7 @@ def execute(self, context: Context): class GRABDOC_OT_remove_mats_by_name(Operator): """Remove materials based on an internal prefixed name""" - bl_idname = "grab_doc.remove_mats_by_name" + bl_idname = "grabdoc.remove_mats_by_name" bl_label = "Remove Mats by Name" bl_options = {'REGISTER', 'UNDO'} @@ -109,7 +109,7 @@ def execute(self, _context: Context): class GRABDOC_OT_quick_remove_selected_mats(UseSelectedOnly, Operator): """Remove all GrabDoc ID materials based on the selected objects from the scene""" - bl_idname = "grab_doc.quick_remove_selected_mats" + bl_idname = "grabdoc.quick_remove_selected_mats" bl_label = "Remove Selected Materials" bl_options = {'REGISTER', 'UNDO'} diff --git a/preferences.py b/preferences.py index b2c9408..9a51f13 100644 --- a/preferences.py +++ b/preferences.py @@ -57,7 +57,7 @@ def update_filename(self, _context: Context): def update_filepath(self, _context: Context): if self.filepath == '//': return - if not os.path.exists(self.filepath): + if not os.path.exists(bpy.path.abspath(self.filepath)): self.filepath = '//' def update_res_x(self, context: Context): @@ -227,11 +227,11 @@ class GRABDOC_PT_presets(PresetPanel, Panel): bl_label = 'Bake Presets' preset_subdir = 'grab_doc' preset_operator = 'script.execute_preset' - preset_add_operator = 'grab_doc.preset_add' + preset_add_operator = 'grabdoc.preset_add' class GRABDOC_OT_add_preset(AddPresetBase, Operator): - bl_idname = "grab_doc.preset_add" + bl_idname = "grabdoc.preset_add" bl_label = "Add a new preset" preset_menu = "GRABDOC_MT_presets" diff --git a/ui.py b/ui.py index d43c53c..b605dcd 100644 --- a/ui.py +++ b/ui.py @@ -34,7 +34,7 @@ def draw(self, _context: Context): return row = self.layout.row(align=True) row.scale_y = 1.5 - row.operator("grab_doc.scene_setup", + row.operator("grabdoc.scene_setup", text="Setup Scene", icon='TOOL_SETTINGS') @@ -51,7 +51,7 @@ def draw_header(self, _context: Context): def draw_header_preset(self, _context: Context): row2 = self.layout.row(align=True) - row2.operator("grab_doc.toggle_camera_view", + row2.operator("grabdoc.toggle_camera_view", text="Leave" if camera_in_3d_view() else "View", icon="OUTLINER_OB_CAMERA") @@ -61,9 +61,9 @@ def draw(self, context: Context): row = self.layout.row(align=True) row.scale_x = row.scale_y = 1.25 - row.operator("grab_doc.scene_setup", + row.operator("grabdoc.scene_setup", text="Rebuild Scene", icon='FILE_REFRESH') - row.operator("grab_doc.scene_cleanup", text="", icon="CANCEL") + row.operator("grabdoc.scene_cleanup", text="", icon="CANCEL") box = layout.box() row = box.row(align=True) @@ -87,7 +87,7 @@ def draw(self, context: Context): row = col.row() row.enabled = not gd.preview_state row.prop(gd, "reference", text='Reference') - row.operator("grab_doc.load_reference", text="", icon='FILE_FOLDER') + row.operator("grabdoc.load_reference", text="", icon='FILE_FOLDER') class GRABDOC_PT_output(GDPanel): @@ -107,7 +107,7 @@ def draw_header_preset(self, context: Context): and not os.path.exists(mt_executable): self.layout.enabled = False self.layout.scale_x = 1 - self.layout.operator("grab_doc.baker_export", + self.layout.operator("grabdoc.baker_export", text="Export", icon="EXPORT") def mt_header_layout(self, layout: UILayout): @@ -125,9 +125,9 @@ def mt_header_layout(self, layout: UILayout): row.prop(preferences, 'mt_executable', text="Executable Path") row = col.row(align=True) row.scale_y = 1.25 - row.operator("grab_doc.bake_marmoset", text="Bake in Marmoset", + row.operator("grabdoc.bake_marmoset", text="Bake in Marmoset", icon="EXPORT").send_type = 'open' - row.operator("grab_doc.bake_marmoset", + row.operator("grabdoc.bake_marmoset", text="", icon='FILE_REFRESH').send_type = 'refresh' def draw(self, context: Context): @@ -146,7 +146,7 @@ def draw(self, context: Context): row.prop(gd, 'engine') row = col2.row() row.prop(gd, 'filepath', text="Path") - row.operator("grab_doc.open_folder", + row.operator("grabdoc.open_folder", text="", icon="FOLDER_REDIRECT") col2.prop(gd, "filename", text="Name") row = col2.row() @@ -213,7 +213,7 @@ def draw_header(self, _context: Context): self.layout.label(icon='SHADING_RENDERED') def draw_header_preset(self, _context: Context): - self.layout.operator("grab_doc.baker_visibility", + self.layout.operator("grabdoc.baker_visibility", emboss=False, text="", icon="SETTINGS") def draw(self, context: Context): @@ -226,15 +226,17 @@ def draw(self, context: Context): row = col.row(align=True) row.alert = True row.scale_y = 1.5 - row.operator("grab_doc.baker_preview_exit", icon="CANCEL") + row.operator("grabdoc.baker_preview_exit", icon="CANCEL") row = col.row(align=True) row.scale_y = 1.1 gd = context.scene.gd baker = getattr(gd, gd.preview_map_type)[gd.preview_index] - row.operator("grab_doc.baker_export_preview", - text=f"Export {baker.NAME}", icon="EXPORT") + row.operator( + "grabdoc.baker_export_preview", + text=f"Export {baker.NAME}", icon="EXPORT" + ).baker_index = baker.index baker.draw(context, layout) @@ -254,7 +256,7 @@ def draw_header(self, _context: Context): def draw_header_preset(self, _context: Context): self.layout.scale_x = .9 - self.layout.operator("grab_doc.baker_pack") + self.layout.operator("grabdoc.baker_pack") def draw(self, context: Context): layout = self.layout @@ -270,7 +272,7 @@ def draw(self, context: Context): col.prop(gd, 'pack_name', text="Suffix") -class BakerPanel(GDPanel): +class GRABDOC_PT_Baker(GDPanel): bl_parent_id = "GRABDOC_PT_bake_maps" bl_options = {'DEFAULT_CLOSED', 'HEADER_LAYOUT_EXPAND'} @@ -300,17 +302,17 @@ def draw_header(self, context: Context): row2.enabled = False row2.separator(factor=.5) row2.prop(self.baker, 'enabled', text="") - preview = row2.operator("grab_doc.baker_preview", text=text) + preview = row2.operator("grabdoc.baker_preview", text=text) preview.map_type = self.baker.ID preview.baker_index = self.baker.index - row2.operator("grab_doc.baker_export_single", + row2.operator("grabdoc.baker_export_single", text="", icon='RENDER_STILL').map_type = self.baker.ID if self.baker == getattr(context.scene.gd, self.baker.ID)[0]: - row.operator("grab_doc.baker_add", + row.operator("grabdoc.baker_add", text="", icon='ADD').map_type = self.baker.ID return - remove = row.operator("grab_doc.baker_remove", text="", icon='TRASH') + remove = row.operator("grabdoc.baker_remove", text="", icon='TRASH') remove.map_type = self.baker.ID remove.baker_index = self.baker.index @@ -329,23 +331,24 @@ def create_baker_panels(): baker_classes = [] for baker_prop in get_baker_collections(): for baker in baker_prop: - if baker.index == -1: - baker.__init__() # pylint: disable=C2801 + baker.__init__() # pylint: disable=C2801 class_name = f"GRABDOC_PT_{baker.ID}_{baker.index}" - panel_cls = type(class_name, (BakerPanel,), {}) + panel_cls = type(class_name, (GRABDOC_PT_Baker,), {}) panel_cls.baker = baker baker_classes.append(panel_cls) return baker_classes def register_baker_panels(): - for cls in BakerPanel.__subclasses__(): + for cls in GRABDOC_PT_Baker.__subclasses__(): try: bpy.utils.unregister_class(cls) + classes.remove(cls) except RuntimeError: continue for cls in create_baker_panels(): bpy.utils.register_class(cls) + classes.append(cls) classes = [ diff --git a/utils/io.py b/utils/io.py index ecd05ee..8a797e9 100644 --- a/utils/io.py +++ b/utils/io.py @@ -1,7 +1,4 @@ -import os - import bpy -from bpy.types import Context from ..constants import Global diff --git a/utils/marmoset.py b/utils/marmoset.py index 2967a06..e64f5a5 100644 --- a/utils/marmoset.py +++ b/utils/marmoset.py @@ -51,7 +51,6 @@ def create_baker(properties: dict): baker.ignoreTransforms = False baker.smoothCage = True baker.ignoreBackfaces = True - baker.multipleTextureSets = False baker.outputWidth = properties['resolution_x'] baker.outputHeight = properties['resolution_y'] # NOTE: Output samples is broken in older APIs @@ -111,12 +110,14 @@ def shader_setup(properties: dict) -> None: def main(): - plugin_path = Path(mset.getPluginPath()).parents[1] + root_path = Path(mset.getPluginPath()).parents[3] + plugin_path = os.path.join(root_path, ".user", "user_default", "GrabDoc") + if not os.path.exists(plugin_path): + plugin_path = plugin_path.replace("user_default", "vscode_development") temp_path = os.path.join(plugin_path, "temp") properties_path = os.path.join(temp_path, "mt_vars.json") - - # Check if file location has been repopulated if not os.path.exists(properties_path): + print("GRABDOC EXPORT FILE NOT FOUND") return with open(properties_path, 'r', encoding='utf-8') as file: @@ -149,8 +150,6 @@ def main(): baker_setup(baker, properties) if properties['auto_bake']: run_auto_baker(baker, properties) - # NOTE: Delete FBX file to avoid temp folder bloat - #os.remove(model_path) shader_setup(properties)