diff --git a/core/common.py b/core/common.py index 0ea4ae0..a58d1f2 100644 --- a/core/common.py +++ b/core/common.py @@ -21,7 +21,7 @@ class SceneMatClass(PropertyGroup): register_class(SceneMatClass) -class material_list_bool: +class MaterialListBool: #For the love that is holy do not ever touch these. If this was java I would make these private #They should only be accessed via context.scene.texture_atlas_Has_Mat_List_Shown #This is so we know if the materials are up to date. messing with these variables directly will make the thing blow up. @@ -31,9 +31,9 @@ class material_list_bool: bool_material_list_expand: dict[str,bool] = {} def set_bool(self, value: bool) -> None: - material_list_bool.bool_material_list_expand[bpy.context.scene.name] = value + MaterialListBool.bool_material_list_expand[bpy.context.scene.name] = value if value == False: - material_list_bool.old_list[bpy.context.scene.name] = [] + MaterialListBool.old_list[bpy.context.scene.name] = [] def get_bool(self) -> bool: newlist: list[Material] = [] @@ -45,20 +45,20 @@ class material_list_bool: newlist.append(mat_slot.material) still_the_same: bool = True - if bpy.context.scene.name in material_list_bool.old_list: + if bpy.context.scene.name in MaterialListBool.old_list: for item in newlist: - if item not in material_list_bool.old_list[bpy.context.scene.name]: + if item not in MaterialListBool.old_list[bpy.context.scene.name]: still_the_same = False break - for item in material_list_bool.old_list[bpy.context.scene.name]: + for item in MaterialListBool.old_list[bpy.context.scene.name]: if item not in newlist: still_the_same = False break else: still_the_same = False - material_list_bool.bool_material_list_expand[bpy.context.scene.name] = still_the_same + MaterialListBool.bool_material_list_expand[bpy.context.scene.name] = still_the_same - return material_list_bool.bool_material_list_expand[bpy.context.scene.name] + return MaterialListBool.bool_material_list_expand[bpy.context.scene.name] ### Clean up material names in the given mesh by removing the '.001' suffix. diff --git a/core/export_resonite.py b/core/export_resonite.py index 92be1e0..c5a668f 100644 --- a/core/export_resonite.py +++ b/core/export_resonite.py @@ -9,7 +9,7 @@ from ..functions.translations import t @register_wrap -class ExportResonite(Operator): +class AvatarToolKit_OT_ExportResonite(Operator): bl_idname = 'avatar_toolkit.export_resonite' bl_label = t("Importer.export_resonite.label") bl_description = t("Importer.export_resonite.desc") diff --git a/core/properties.py b/core/properties.py index 9545d6b..45a814f 100644 --- a/core/properties.py +++ b/core/properties.py @@ -4,7 +4,7 @@ from ..core.register import register_property from bpy.types import Scene, Object, Material, Context from bpy.props import BoolProperty, EnumProperty, IntProperty, CollectionProperty, StringProperty, FloatVectorProperty, PointerProperty from ..core.addon_preferences import get_preference -from ..core.common import SceneMatClass, material_list_bool, get_armatures, get_mesh_items +from ..core.common import SceneMatClass, MaterialListBool, get_armatures, get_mesh_items def register() -> None: default_language = get_preference("language", 0) @@ -106,8 +106,8 @@ def register() -> None: register_property((Scene, "texture_atlas_Has_Mat_List_Shown", BoolProperty( default=False, - get=material_list_bool.get_bool, - set=material_list_bool.set_bool))) + get=MaterialListBool.get_bool, + set=MaterialListBool.set_bool))) def unregister() -> None: diff --git a/functions/additional_tools.py b/functions/additional_tools.py index e5cb05a..fe1a7c1 100644 --- a/functions/additional_tools.py +++ b/functions/additional_tools.py @@ -5,7 +5,7 @@ from ..core.common import get_selected_armature, is_valid_armature, get_all_mesh from ..functions.translations import t @register_wrap -class ApplyTransforms(Operator): +class AvatarToolKit_OT_ApplyTransforms(Operator): bl_idname = "avatar_toolkit.apply_transforms" bl_label = t("Tools.apply_transforms.label") bl_description = t("Tools.apply_transforms.desc") diff --git a/functions/atlas_materials.py b/functions/atlas_materials.py index 4c5bf83..819d7b5 100644 --- a/functions/atlas_materials.py +++ b/functions/atlas_materials.py @@ -2,13 +2,11 @@ from pathlib import Path import numpy import bpy -import re import os from typing import List, Tuple, Optional -from mathutils import Vector from bpy.types import Material, Operator, Context, Object, Image, Mesh, MeshUVLoopLayer, Float2AttributeValue, ShaderNodeTexImage, ShaderNodeBsdfPrincipled, ShaderNodeNormalMap from ..core.register import register_wrap -from ..core.common import SceneMatClass, material_list_bool +from ..core.common import SceneMatClass, MaterialListBool from ..core.packer.rectangle_packer import MaterialImageList, BinPacker from ..functions.translations import t @@ -113,7 +111,7 @@ def prep_images_in_scene(context: Context) -> list[MaterialImageList]: @register_wrap -class Atlas_Materials(Operator): +class AvatarToolKit_OT_AtlasMaterials(Operator): bl_idname = "avatar_toolkit.atlas_materials" bl_label = t("TextureAtlas.atlas_materials") diff --git a/functions/combine_materials.py b/functions/combine_materials.py index e58056d..b0bf9df 100644 --- a/functions/combine_materials.py +++ b/functions/combine_materials.py @@ -53,7 +53,7 @@ def get_base_name(name: str) -> str: return mat_match.group(1) if mat_match else name @register_wrap -class CombineMaterials(Operator): +class AvatarToolKit_OT_CombineMaterials(Operator): bl_idname = "avatar_toolkit.combine_materials" bl_label = t("Optimization.combine_materials.label") bl_description = t("Optimization.combine_materials.desc") diff --git a/functions/digitigrade_legs.py b/functions/digitigrade_legs.py index 0544e6a..3b5dc56 100644 --- a/functions/digitigrade_legs.py +++ b/functions/digitigrade_legs.py @@ -6,8 +6,8 @@ import re @register_wrap -class CreateDigitigradeLegs(bpy.types.Operator): - bl_idname = "avatar_toolkit.createdigitigradelegs" +class AvatarToolKit_OT_CreateDigitigradeLegs(bpy.types.Operator): + bl_idname = "avatar_toolkit.create_digitigrade_legs" bl_label = t('Tools.create_digitigrade_legs.label') bl_description = t('Tools.create_digitigrade_legs.desc') diff --git a/functions/import_anything.py b/functions/import_anything.py index 13216a8..032fb2f 100644 --- a/functions/import_anything.py +++ b/functions/import_anything.py @@ -3,14 +3,13 @@ from bpy.types import Operator from bpy_extras.io_utils import ImportHelper from ..core.register import register_wrap from ..core.importer import imports, import_types -from ..core.common import remove_default_objects +from ..core.common import remove_default_objects, open_web_after_delay_multi_threaded from ..functions.translations import t import pathlib import os -from ..core import common @register_wrap -class ImportAnyModel(Operator, ImportHelper): +class AvatarToolKit_OT_ImportAnyModel(Operator, ImportHelper): bl_idname = 'avatar_toolkit.import_any_model' bl_label = t('Tools.import_any_model.label') bl_description = t('Tools.import_any_model.desc') @@ -24,7 +23,7 @@ class ImportAnyModel(Operator, ImportHelper): #since I wrote this myself, a bit more efficent than cats. mostly - @989onan def execute(self, context: bpy.types.Context): file_grouping_dict: dict[str, list[dict[str,str]]] = dict()#group our files so our importers can import them together. in the case of OBJ+MTL and others that need grouped files, this is extremely important. - common.remove_default_objects() + remove_default_objects() #check if we are importing multiple files is_multi = False try: @@ -69,9 +68,9 @@ class ImportAnyModel(Operator, ImportHelper): else: import_types[file_group_name]("",files,self.filepath) #give an empty directory, works just fine for 90% except AttributeError as e: - print("Warning, you may not have the required importer!") + print("Warning, you may not have the required importer for extension type \"{extension}\"!".format(extension = file_group_name)) - common.open_web_after_delay_multi_threaded(delay=12, url=t('Importing.importer_search_term').format(extension = file_group_name)) + open_web_after_delay_multi_threaded(delay=12, url=t('Importing.importer_search_term').format(extension = file_group_name)) self.report({'ERROR'},t('Importing.need_importer').format(extension = file_group_name)) diff --git a/functions/join_meshes.py b/functions/join_meshes.py index d3f74b9..09776ae 100644 --- a/functions/join_meshes.py +++ b/functions/join_meshes.py @@ -6,7 +6,7 @@ from ..core.common import fix_uv_coordinates, get_selected_armature, is_valid_ar from ..functions.translations import t @register_wrap -class JoinAllMeshes(Operator): +class AvatarToolKit_OT_JoinAllMeshes(Operator): bl_idname = "avatar_toolkit.join_all_meshes" bl_label = t("Optimization.join_all_meshes.label") bl_description = t("Optimization.join_all_meshes.desc") @@ -72,7 +72,7 @@ class JoinAllMeshes(Operator): finish_progress(context) @register_wrap -class JoinSelectedMeshes(Operator): +class AvatarToolKit_OT_JoinSelectedMeshes(Operator): bl_idname = "avatar_toolkit.join_selected_meshes" bl_label = t("Optimization.join_selected_meshes.label") bl_description = t("Optimization.join_selected_meshes.desc") diff --git a/functions/remove_doubles_safely.py b/functions/remove_doubles_safely.py index 887a22b..9582740 100644 --- a/functions/remove_doubles_safely.py +++ b/functions/remove_doubles_safely.py @@ -12,7 +12,7 @@ class meshEntry(TypedDict): cur_vertex_pass: int @register_wrap -class RemoveDoublesSafelyAdvanced(Operator): +class AvatarToolKit_OT_RemoveDoublesSafelyAdvanced(Operator): bl_idname = "avatar_toolkit.remove_doubles_safely_advanced" bl_label = t("Optimization.remove_doubles_safely_advanced.label") bl_description = t("Optimization.remove_doubles_safely_advanced.desc") @@ -30,7 +30,7 @@ class RemoveDoublesSafelyAdvanced(Operator): bpy.ops.avatar_toolkit.remove_doubles_safely('INVOKE_DEFAULT',advanced=True,merge_distance=self.merge_distance) return {'FINISHED'} @register_wrap -class RemoveDoublesSafely(Operator): +class AvatarToolKit_OT_RemoveDoublesSafely(Operator): bl_idname = "avatar_toolkit.remove_doubles_safely" bl_label = t("Optimization.remove_doubles_safely.label") bl_description = t("Optimization.remove_doubles_safely.desc") diff --git a/functions/resonite_functions.py b/functions/resonite_functions.py index a8a91b2..1f32e2e 100644 --- a/functions/resonite_functions.py +++ b/functions/resonite_functions.py @@ -8,7 +8,7 @@ from ..core.common import get_selected_armature, simplify_bonename, is_valid_arm from ..functions.translations import t @register_wrap -class ConvertToResonite(Operator): +class AvatarToolKit_OT_ConvertToResonite(Operator): bl_idname = 'avatar_toolkit.convert_to_resonite' bl_label = t('Tools.convert_to_resonite.label') bl_description = t('Tools.convert_to_resonite.desc') diff --git a/functions/seperate_by.py b/functions/seperate_by.py index 52e507a..8902f8c 100644 --- a/functions/seperate_by.py +++ b/functions/seperate_by.py @@ -1,11 +1,10 @@ import bpy from bpy.types import Context, Operator from ..core.register import register_wrap -from ..core.common import get_selected_armature, is_valid_armature, select_current_armature from ..functions.translations import t @register_wrap -class SeparateByMaterials(Operator): +class AvatarToolKit_OT_SeparateByMaterials(Operator): bl_idname = "avatar_toolkit.separate_by_materials" bl_label = t("Tools.separate_by_materials.label") bl_description = t("Tools.separate_by_materials.desc") @@ -25,7 +24,7 @@ class SeparateByMaterials(Operator): return {'FINISHED'} @register_wrap -class SeparateByLooseParts(Operator): +class AvatarToolKit_OT_SeparateByLooseParts(Operator): bl_idname = "avatar_toolkit.separate_by_loose_parts" bl_label = t("Tools.separate_by_loose_parts.label") bl_description = t("Tools.separate_by_loose_parts.desc") diff --git a/functions/viseme.py b/functions/viseme.py index db18bb9..7f20e73 100644 --- a/functions/viseme.py +++ b/functions/viseme.py @@ -6,7 +6,7 @@ from typing import List, Tuple from ..core.common import get_selected_armature, is_valid_armature, get_all_meshes, init_progress, update_progress, finish_progress @register_wrap -class AutoVisemeButton(bpy.types.Operator): +class AvatarToolKit_OT_AutoVisemeButton(bpy.types.Operator): bl_idname = 'avatar_toolkit.create_visemes' bl_label = t('AutoVisemeButton.label') bl_description = t('AutoVisemeButton.desc') diff --git a/ui/atlas_materials.py b/ui/atlas_materials.py index 7d0f7c3..09a7d1f 100644 --- a/ui/atlas_materials.py +++ b/ui/atlas_materials.py @@ -1,13 +1,13 @@ from bpy.types import UIList, Panel, UILayout, Object, Context,Material, Operator import bpy from ..core.register import register_wrap -from .panel import AvatarToolkitPanel -from ..core.common import SceneMatClass, material_list_bool, get_selected_armature -from ..functions.atlas_materials import Atlas_Materials +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME +from ..core.common import SceneMatClass, MaterialListBool, get_selected_armature +from ..functions.atlas_materials import AvatarToolKit_OT_AtlasMaterials from ..functions.translations import t @register_wrap -class ExpandSection_Materials(Operator): +class AvatarToolKit_OT_ExpandSectionMaterials(Operator): bl_idname = 'avatar_toolkit.expand_section_materials' bl_label = "" bl_description = "" @@ -28,13 +28,13 @@ class ExpandSection_Materials(Operator): newlist.append(mat_slot.material) newitem: SceneMatClass = context.scene.materials.add() newitem.mat = mat_slot.material - material_list_bool.old_list[context.scene.name] = newlist + MaterialListBool.old_list[context.scene.name] = newlist else: context.scene.texture_atlas_Has_Mat_List_Shown = False return {'FINISHED'} @register_wrap -class MaterialTextureAtlasProperties(UIList): +class AvatarToolKit_UL_MaterialTextureAtlasProperties(UIList): bl_label = t("TextureAtlas.material_list_label") bl_idname = "Material_UL_avatar_toolkit_texture_atlas_mat_list_mat" bl_space_type = 'VIEW_3D' @@ -59,13 +59,13 @@ class MaterialTextureAtlasProperties(UIList): col.prop(item.mat, "texture_atlas_roughness") @register_wrap -class TextureAtlasPanel(Panel): +class AvatarToolKit_PT_TextureAtlasPanel(Panel): bl_label = t("TextureAtlas.label") bl_idname = "OBJECT_PT_avatar_toolkit_texture_atlas" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 4 def draw(self, context: Context): @@ -77,12 +77,12 @@ class TextureAtlasPanel(Panel): boxoutter = row.box() direction_icon = 'RIGHTARROW' if not context.scene.texture_atlas_Has_Mat_List_Shown else 'DOWNARROW_HLT' row = boxoutter.row() - row.operator(ExpandSection_Materials.bl_idname, text=(t("TextureAtlas.reload_list") if not context.scene.texture_atlas_Has_Mat_List_Shown else t("TextureAtlas.loaded_list")), icon=direction_icon) + row.operator(AvatarToolKit_OT_ExpandSectionMaterials.bl_idname, text=(t("TextureAtlas.reload_list") if not context.scene.texture_atlas_Has_Mat_List_Shown else t("TextureAtlas.loaded_list")), icon=direction_icon) if context.scene.texture_atlas_Has_Mat_List_Shown: row = boxoutter.row() - row.template_list(MaterialTextureAtlasProperties.bl_idname, 'material_list', context.scene, 'materials', + row.template_list(AvatarToolKit_UL_MaterialTextureAtlasProperties.bl_idname, 'material_list', context.scene, 'materials', context.scene, 'texture_atlas_material_index', rows=12, type='DEFAULT') row = layout.row() - row.operator(Atlas_Materials.bl_idname, text=t("TextureAtlas.atlas_materials")) + row.operator(AvatarToolKit_OT_AtlasMaterials.bl_idname, text=t("TextureAtlas.atlas_materials")) else: layout.label(text=t("Tools.select_armature"), icon='ERROR') diff --git a/ui/optimization.py b/ui/optimization.py index 6b1d1b3..eefba12 100644 --- a/ui/optimization.py +++ b/ui/optimization.py @@ -1,18 +1,20 @@ import bpy from ..core.register import register_wrap -from .panel import AvatarToolkitPanel +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME from ..functions.translations import t -from ..functions.remove_doubles_safely import RemoveDoublesSafely, RemoveDoublesSafelyAdvanced +from ..functions.remove_doubles_safely import AvatarToolKit_OT_RemoveDoublesSafely, AvatarToolKit_OT_RemoveDoublesSafelyAdvanced from ..core.common import get_selected_armature +from ..functions.join_meshes import AvatarToolKit_OT_JoinAllMeshes, AvatarToolKit_OT_JoinSelectedMeshes +from ..functions.combine_materials import AvatarToolKit_OT_CombineMaterials @register_wrap -class AvatarToolkitOptimizationPanel(bpy.types.Panel): +class AvatarToolkit_PT_OptimizationPanel(bpy.types.Panel): bl_label = t("Optimization.label") bl_idname = "OBJECT_PT_avatar_toolkit_optimization" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 2 def draw(self, context): @@ -24,18 +26,18 @@ class AvatarToolkitOptimizationPanel(bpy.types.Panel): row = layout.row() row.scale_y = 1.2 - row.operator("avatar_toolkit.combine_materials", text=t("Optimization.combine_materials.label"), icon='MATERIAL') + row.operator(AvatarToolKit_OT_CombineMaterials.bl_idname, text=t("Optimization.combine_materials.label"), icon='MATERIAL') row = layout.row(align=True) row.scale_y = 1.2 - row.operator(RemoveDoublesSafely.bl_idname, text=t("Optimization.remove_doubles_safely.label"), icon='SNAP_VERTEX') - row.operator(RemoveDoublesSafelyAdvanced.bl_idname, text=t("Optimization.remove_doubles_safely_advanced.label"), icon = "ACTION") + row.operator(AvatarToolKit_OT_RemoveDoublesSafely.bl_idname, text=t("Optimization.remove_doubles_safely.label"), icon='SNAP_VERTEX') + row.operator(AvatarToolKit_OT_RemoveDoublesSafelyAdvanced.bl_idname, text=t("Optimization.remove_doubles_safely_advanced.label"), icon = "ACTION") layout.separator(factor=0.5) layout.label(text=t("Optimization.joinmeshes.label"), icon='SETTINGS') row = layout.row(align=True) row.scale_y = 1.2 - row.operator("avatar_toolkit.join_all_meshes", text=t("Optimization.join_all_meshes.label"), icon='OUTLINER_OB_MESH') - row.operator("avatar_toolkit.join_selected_meshes", text=t("Optimization.join_selected_meshes.label"), icon='STICKY_UVS_LOC') + row.operator(AvatarToolKit_OT_JoinAllMeshes.bl_idname, text=t("Optimization.join_all_meshes.label"), icon='OUTLINER_OB_MESH') + row.operator(AvatarToolKit_OT_JoinSelectedMeshes.bl_idname, text=t("Optimization.join_selected_meshes.label"), icon='STICKY_UVS_LOC') else: layout.label(text=t("Optimization.select_armature"), icon='ERROR') diff --git a/ui/panel.py b/ui/panel.py index 629fee3..bd2dd73 100644 --- a/ui/panel.py +++ b/ui/panel.py @@ -2,13 +2,15 @@ import bpy from ..core.register import register_wrap from ..functions.translations import t +CATEGORY_NAME = "Avatar Toolkit" + @register_wrap -class AvatarToolkitPanel(bpy.types.Panel): +class AvatarToolKit_PT_AvatarToolkitPanel(bpy.types.Panel): bl_label = t("AvatarToolkit.label") bl_idname = "OBJECT_PT_avatar_toolkit" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" + bl_category = CATEGORY_NAME def draw(self, context): layout = self.layout diff --git a/ui/quick_access.py b/ui/quick_access.py index 0825bcd..6020477 100644 --- a/ui/quick_access.py +++ b/ui/quick_access.py @@ -1,23 +1,23 @@ import bpy from ..core.register import register_wrap -from .panel import AvatarToolkitPanel +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME +from ..core.export_resonite import AvatarToolKit_OT_ExportResonite from bpy.types import Context, Mesh, Panel, Operator from ..functions.translations import t from ..core.import_pmx import import_pmx from ..core.import_pmd import import_pmd -from ..functions.import_anything import ImportAnyModel +from ..functions.import_anything import AvatarToolKit_OT_ImportAnyModel from ..core.common import get_selected_armature, set_selected_armature, get_all_meshes -@register_wrap @register_wrap class AvatarToolkitQuickAccessPanel(Panel): bl_label = t("Quick_Access.label") bl_idname = "OBJECT_PT_avatar_toolkit_quick_access" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 1 def draw(self, context: Context): @@ -35,8 +35,8 @@ class AvatarToolkitQuickAccessPanel(Panel): row = layout.row(align=True) row.scale_y = 1.5 - row.operator(ImportAnyModel.bl_idname, text=t("Quick_Access.import"), icon='IMPORT') - row.operator(AVATAR_TOOLKIT_OT_export_menu.bl_idname, text=t("Quick_Access.export"), icon='EXPORT') + row.operator(AvatarToolKit_OT_ImportAnyModel.bl_idname, text=t("Quick_Access.import"), icon='IMPORT') + row.operator(AVATAR_TOOLKIT_OT_ExportMenu.bl_idname, text=t("Quick_Access.export"), icon='EXPORT') if get_selected_armature(context) != None: if(context.mode == "POSE"): @@ -50,6 +50,40 @@ class AvatarToolkitQuickAccessPanel(Panel): row = layout.row(align=True) row.operator(AvatarToolkit_OT_StartPoseMode.bl_idname, text=t("Quick_Access.start_pose_mode.label"), icon='POSE_HLT') +@register_wrap +class AVATAR_TOOLKIT_OT_ExportMenu(bpy.types.Operator): + bl_idname = "avatar_toolkit.export_menu" + bl_label = t("Quick_Access.export_menu.label") + bl_description = t("Quick_Access.export_menu.desc") + + @classmethod + def poll(cls, context): + return any(obj.type == 'MESH' for obj in context.scene.objects) + + def execute(self, context: Context) -> set[str]: + return {'FINISHED'} + + def invoke(self, context: Context, event): + wm = context.window_manager + return wm.invoke_popup(self, width=200) + + def draw(self, context: Context): + layout = self.layout + layout.label(text=t("Quick_Access.select_export.label"), icon='EXPORT') + layout.operator(AvatarToolKit_OT_ExportResonite.bl_idname, text=t("Quick_Access.select_export_resonite.label"), icon='SCENE_DATA') + layout.operator(AVATAR_TOOLKIT_OT_ExportFbx.bl_idname, text=t("Quick_Access.export_fbx.label"), icon='OBJECT_DATA') + +@register_wrap +class AVATAR_TOOLKIT_OT_ExportFbx(bpy.types.Operator): + bl_idname = 'avatar_toolkit.export_fbx' + bl_label = t("Quick_Access.export_fbx.label") + bl_description = t("Quick_Access.export_fbx.desc") + bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} + + def execute(self, context) -> set[str]: + bpy.ops.export_scene.fbx('INVOKE_DEFAULT') + return {'FINISHED'} + @register_wrap class AvatarToolkit_OT_StartPoseMode(Operator): bl_idname = 'avatar_toolkit.start_pose_mode' @@ -62,18 +96,12 @@ class AvatarToolkit_OT_StartPoseMode(Operator): return get_selected_armature(context) != None and context.mode != "POSE" def execute(self, context: Context) -> set[str]: - - #give an active object so the next line doesn't throw an error. context.view_layer.objects.active = get_selected_armature(context) - bpy.ops.object.mode_set(mode='OBJECT') - - #deselect everything and select just our armature, then go into pose on just our selected armature. - @989onan bpy.ops.object.select_all(action='DESELECT') context.view_layer.objects.active = get_selected_armature(context) context.view_layer.objects.active.select_set(True) bpy.ops.object.mode_set(mode='POSE') - return {'FINISHED'} @register_wrap @@ -88,14 +116,11 @@ class AvatarToolkit_OT_StopPoseMode(Operator): return get_selected_armature(context) != None and context.mode == "POSE" def execute(self, context: Context) -> set[str]: - #this is done so that transforms are cleared but user selection is respected. - @989onan bpy.ops.pose.transforms_clear() bpy.ops.pose.select_all(action="INVERT") bpy.ops.pose.transforms_clear() bpy.ops.pose.select_all(action="INVERT") - bpy.ops.object.mode_set(mode='OBJECT') - return {'FINISHED'} @register_wrap @@ -112,10 +137,8 @@ class AvatarToolkit_OT_ApplyPoseAsShapekey(Operator): def execute(self, context: Context): bpy.ops.object.mode_set(mode="OBJECT") for obj in get_all_meshes(context): - modifier_armature_name: str = "" context.view_layer.objects.active = obj - bpy.ops.object.mode_set(mode="OBJECT") bpy.ops.object.select_all(action="DESELECT") context.view_layer.objects.active = obj @@ -125,7 +148,6 @@ class AvatarToolkit_OT_ApplyPoseAsShapekey(Operator): arm_modifier: bpy.types.ArmatureModifier = modifier modifier_armature_name = arm_modifier.object.name bpy.ops.object.modifier_apply_as_shapekey(modifier=modifier_armature_name,keep_modifier=True,report=True) - return {'FINISHED'} @register_wrap @@ -143,8 +165,6 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator): for obj in get_all_meshes(context): mesh_data: Mesh = obj.data - - if mesh_data.shape_keys: shape_key_obj_list: list[bpy.types.Object] = [] modifier_armature_name: str = "" @@ -163,12 +183,10 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator): context.view_layer.objects.active = obj obj.select_set(True) - #create duplicate of object bpy.ops.object.duplicate() shape_obj = context.view_layer.objects.active - #make current shapekey a separate object shape_obj.active_shape_key_index = idx shape_obj.name = shape.name @@ -181,10 +199,7 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator): bpy.ops.object.modifier_apply(modifier=modifier_armature_name) - #for modifier_name in [i.name for i in shape_obj.modifiers]: - # bpy.ops.object.modifier_remove(modifier=modifier_name) - - shape_key_obj_list.append(shape_obj) #add to a list of shape key objects + shape_key_obj_list.append(shape_obj) context.view_layer.objects.active = obj bpy.ops.object.mode_set(mode="OBJECT") @@ -202,7 +217,6 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator): bpy.ops.object.join_shapes() except: self.report({'ERROR'}, t("Quick_Access.apply_armature_failed")) - #delete shapekey objects to not leave ourselves in a bad exit state - @989onan context.view_layer.objects.active = shape_key_obj_list[0] obj.select_set(False) bpy.ops.object.delete(confirm=False) @@ -233,37 +247,3 @@ class AvatarToolkit_OT_ApplyPoseAsRest(Operator): bpy.ops.pose.armature_apply(selected=False) return {'FINISHED'} - -@register_wrap -class AVATAR_TOOLKIT_OT_export_menu(Operator): - bl_idname = "avatar_toolkit.export_menu" - bl_label = t("Quick_Access.export_menu.label") - bl_description = t("Quick_Access.export_menu.desc") - - @classmethod - def poll(cls, context): - return any(obj.type == 'MESH' for obj in context.scene.objects) - - def execute(self, context: Context) -> set[str]: - return {'FINISHED'} - - def invoke(self, context: Context, event): - wm = context.window_manager - return wm.invoke_popup(self, width=200) - - def draw(self, context: Context): - layout = self.layout - layout.label(text=t("Quick_Access.select_export.label"), icon='EXPORT') - layout.operator("avatar_toolkit.export_resonite", text=t("Quick_Access.select_export_resonite.label"), icon='SCENE_DATA') - layout.operator("avatar_toolkit.export_fbx", text=t("Quick_Access.export_fbx.label"), icon='OBJECT_DATA') - -@register_wrap -class AVATAR_TOOLKIT_OT_export_fbx(Operator): - bl_idname = 'avatar_toolkit.export_fbx' - bl_label = t("Quick_Access.export_fbx.label") - bl_description = t("Quick_Access.export_fbx.desc") - bl_options = {'REGISTER', 'UNDO', 'INTERNAL'} - - def execute(self, context) -> set[str]: - bpy.ops.export_scene.fbx('INVOKE_DEFAULT') - return {'FINISHED'} diff --git a/ui/settings.py b/ui/settings.py index 48ae72b..b88d514 100644 --- a/ui/settings.py +++ b/ui/settings.py @@ -1,6 +1,6 @@ import bpy from ..core.register import register_wrap -from .panel import AvatarToolkitPanel +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME from ..functions.translations import t @register_wrap @@ -9,8 +9,8 @@ class AvatarToolkitSettingsPanel(bpy.types.Panel): bl_idname = "OBJECT_PT_avatar_toolkit_settings" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 6 def draw(self, context): diff --git a/ui/tools.py b/ui/tools.py index 62dde6c..0acfc80 100644 --- a/ui/tools.py +++ b/ui/tools.py @@ -1,21 +1,22 @@ import bpy from ..core.register import register_wrap -from .panel import AvatarToolkitPanel +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME from bpy.types import Context -from ..functions.digitigrade_legs import CreateDigitigradeLegs +from ..functions.digitigrade_legs import AvatarToolKit_OT_CreateDigitigradeLegs +from ..functions.resonite_functions import AvatarToolKit_OT_ConvertToResonite from ..functions.translations import t from ..core.common import get_selected_armature -from ..functions.seperate_by import SeparateByMaterials, SeparateByLooseParts -from ..functions.additional_tools import ApplyTransforms +from ..functions.seperate_by import AvatarToolKit_OT_SeparateByMaterials, AvatarToolKit_OT_SeparateByLooseParts +from ..functions.additional_tools import AvatarToolKit_OT_ApplyTransforms @register_wrap -class AvatarToolkitToolsPanel(bpy.types.Panel): +class AvatarToolkit_PT_ToolsPanel(bpy.types.Panel): bl_label = t("Tools.label") bl_idname = "OBJECT_PT_avatar_toolkit_tools" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 3 def draw(self, context: Context): @@ -28,15 +29,15 @@ class AvatarToolkitToolsPanel(bpy.types.Panel): row = layout.row(align=True) row.scale_y = 1.5 - row.operator("avatar_toolkit.convert_to_resonite", text=t("Tools.convert_to_resonite.label"), icon='SCENE_DATA') + row.operator(AvatarToolKit_OT_ConvertToResonite.bl_idname, text=t("Tools.convert_to_resonite.label"), icon='SCENE_DATA') row = layout.row(align=True) - row.operator(CreateDigitigradeLegs.bl_idname, text=t("Tools.create_digitigrade_legs.label"), icon='BONE_DATA') + row.operator(AvatarToolKit_OT_CreateDigitigradeLegs.bl_idname, text=t("Tools.create_digitigrade_legs.label"), icon='BONE_DATA') layout.separator() row = layout.row(align=True) layout.label(text=t("Tools.separate_by.label"), icon='MESH_DATA') - row.operator(SeparateByMaterials.bl_idname, text=t("Tools.separate_by_materials.label"), icon='MATERIAL') - row.operator(SeparateByLooseParts.bl_idname, text=t("Tools.separate_by_loose_parts.label"), icon='OUTLINER_OB_MESH') + row.operator(AvatarToolKit_OT_SeparateByMaterials.bl_idname, text=t("Tools.separate_by_materials.label"), icon='MATERIAL') + row.operator(AvatarToolKit_OT_SeparateByLooseParts.bl_idname, text=t("Tools.separate_by_loose_parts.label"), icon='OUTLINER_OB_MESH') row = layout.row(align=True) - row.operator(ApplyTransforms.bl_idname, text=t("Tools.apply_transforms.label"), icon='OBJECT_ORIGIN') + row.operator(AvatarToolKit_OT_ApplyTransforms.bl_idname, text=t("Tools.apply_transforms.label"), icon='OBJECT_ORIGIN') else: layout.label(text=t("Tools.select_armature"), icon='ERROR') diff --git a/ui/viseme.py b/ui/viseme.py index 446daff..8c6fc3d 100644 --- a/ui/viseme.py +++ b/ui/viseme.py @@ -1,5 +1,7 @@ import bpy from ..core.register import register_wrap +from .panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME +from ..functions.viseme import AvatarToolKit_OT_AutoVisemeButton from ..functions.translations import t from ..core.common import get_selected_armature @@ -9,8 +11,8 @@ class AvatarToolkitVisemePanel(bpy.types.Panel): bl_idname = "OBJECT_PT_avatar_toolkit_viseme" bl_space_type = 'VIEW_3D' bl_region_type = 'UI' - bl_category = "Avatar Toolkit" - bl_parent_id = "OBJECT_PT_avatar_toolkit" + bl_category = CATEGORY_NAME + bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname bl_order = 5 def draw(self, context: bpy.types.Context) -> None: @@ -32,7 +34,7 @@ class AvatarToolkitVisemePanel(bpy.types.Panel): row = layout.row() row.scale_y = 1.2 - row.operator("avatar_toolkit.create_visemes", text=t('VisemePanel.create_visemes'), icon='TRIA_RIGHT') + row.operator(AvatarToolKit_OT_AutoVisemeButton.bl_idname, text=t('VisemePanel.create_visemes'), icon='TRIA_RIGHT') else: layout.label(text=t('VisemePanel.error.noShapekeys'), icon='ERROR') else: