From 7e584e36488f96b07ef100fdaff8da788bd06641 Mon Sep 17 00:00:00 2001 From: Yusarina Date: Tue, 3 Dec 2024 01:26:10 +0000 Subject: [PATCH] Fixes This fixes is to get everything working on the new auto load and properties system. Also some other small fixes. --- core/common.py | 17 +- core/properties.py | 17 +- core/translations.py | 6 +- core/updater.py | 2 +- functions/armature_modifying.py | 9 ++ functions/atlas_materials.py | 270 +++++++++++++++++--------------- functions/mesh_tools.py | 4 +- functions/mmd_functions.py | 1 - functions/translations.py | 97 ------------ functions/viseme.py | 10 +- 10 files changed, 189 insertions(+), 244 deletions(-) delete mode 100644 functions/translations.py diff --git a/core/common.py b/core/common.py index b1f3644..2b4c702 100644 --- a/core/common.py +++ b/core/common.py @@ -161,15 +161,15 @@ def get_armatures(self, context: Context) -> List[Tuple[str, str, str]]: return armatures def get_armatures_that_are_not_selected(self, context: Context) -> List[Tuple[str, str, str]]: - armatures = [(obj.name, obj.name, "") for obj in bpy.data.objects if ((obj.type == 'ARMATURE') and (obj.name != context.scene.selected_armature))] + armatures = [(obj.name, obj.name, "") for obj in bpy.data.objects if ((obj.type == 'ARMATURE') and (obj.name != context.scene.avatar_toolkit.selected_armature))] if not armatures: return [('NONE', 'No Other Armature', '')] return armatures def get_selected_armature(context: Context) -> Optional[Object]: try: - if hasattr(context.scene, 'selected_armature'): - armature_name = context.scene.selected_armature + if hasattr(context.scene, 'avatar_toolkit'): + armature_name = context.scene.avatar_toolkit.selected_armature if isinstance(armature_name, bytes): try: armature_name = armature_name.decode('utf-8') @@ -209,9 +209,8 @@ def get_merge_armature_source(context: Context) -> Optional[Object]: pass return None - def set_selected_armature(context: Context, armature: Optional[Object]) -> None: - context.scene.selected_armature = armature.name if armature else "" + context.scene.avatar_toolkit.selected_armature = armature.name if armature else "" def is_valid_armature(armature: Object) -> bool: if not armature or armature.type != 'ARMATURE': @@ -451,12 +450,12 @@ def remove_default_objects(): def init_progress(context, steps): context.window_manager.progress_begin(0, 100) - context.scene.avatar_toolkit_progress_steps = steps - context.scene.avatar_toolkit_progress_current = 0 + context.scene.avatar_toolkit.progress_steps = steps + context.scene.avatar_toolkit.progress_current = 0 def update_progress(self, context, message): - context.scene.avatar_toolkit_progress_current += 1 - progress = (context.scene.avatar_toolkit_progress_current / context.scene.avatar_toolkit_progress_steps) * 100 + context.scene.avatar_toolkit.progress_current += 1 + progress = (context.scene.avatar_toolkit.progress_current / context.scene.avatar_toolkit.progress_steps) * 100 context.window_manager.progress_update(progress) context.area.header_text_set(message) self.report({'INFO'}, message) diff --git a/core/properties.py b/core/properties.py index 5d5c755..d920160 100644 --- a/core/properties.py +++ b/core/properties.py @@ -99,6 +99,13 @@ class AvatarToolkitSceneProperties(PropertyGroup): set=MaterialListBool.set_bool ) + avatar_toolkit_updater_version_list: EnumProperty( + items=get_version_list, + name="Version List", + description="List of available versions" + ) + + class AvatarToolkitMaterialProperties(PropertyGroup): material_expanded: BoolProperty( name="Expand Material", @@ -113,11 +120,13 @@ class AvatarToolkitMaterialProperties(PropertyGroup): ) def get_texture_node_list(self, context): - if self.use_nodes: + # Access the material through the property group's id_data + material = self.id_data + if material and material.use_nodes: nodes = [(i.image.name if i.image else i.name+"_image", - i.image.name if i.image else "node with no image...", - i.image.name if i.image else i.name, index+1) - for index, i in enumerate(self.node_tree.nodes) + i.image.name if i.image else "node with no image...", + i.image.name if i.image else i.name, index+1) + for index, i in enumerate(material.node_tree.nodes) if i.bl_idname == "ShaderNodeTexImage"] if not nodes: nodes = [("Error", "No images found", "Error", 0)] diff --git a/core/translations.py b/core/translations.py index c123ad7..f047964 100644 --- a/core/translations.py +++ b/core/translations.py @@ -84,11 +84,11 @@ def get_languages_list(self, context) -> List[Tuple[str, str, str]]: return [(str(i), get_language_display_name(lang), f"Use {lang} language") for i, lang in enumerate(languages)] def update_language(self, context): - print(f"Updating language to: {self.avatar_toolkit_language}") # Debug print - save_preference("language", int(self.avatar_toolkit_language)) + print(f"Updating language to: {self.language}") # Debug print + save_preference("language", int(self.language)) load_translations() # Set a flag to indicate that a language change has occurred - context.scene.avatar_toolkit_language_changed = True + context.scene.avatar_toolkit.language_changed = True # Show popup after language change bpy.ops.avatar_toolkit.translation_restart_popup('INVOKE_DEFAULT') diff --git a/core/updater.py b/core/updater.py index 53eb248..4ccbd23 100644 --- a/core/updater.py +++ b/core/updater.py @@ -287,7 +287,7 @@ def draw_updater_panel(context: bpy.types.Context, layout: bpy.types.UILayout) - col.separator() row = col.row(align=True) - row.prop(context.scene, 'avatar_toolkit_updater_version_list', text='') + row.prop(context.scene.avatar_toolkit, 'avatar_toolkit_updater_version_list', text='') row.operator(AvatarToolkit_OT_UpdateToLatest.bl_idname, text=t('Updater.UpdateToSelectedButton.label')) col.separator() diff --git a/functions/armature_modifying.py b/functions/armature_modifying.py index f8c1acd..7edaf97 100644 --- a/functions/armature_modifying.py +++ b/functions/armature_modifying.py @@ -156,6 +156,15 @@ class AvatarToolkit_OT_RemoveZeroWeightBones(Operator): 'matrix': bone.matrix.copy(), 'parent': bone.parent.name if bone.parent else None } + # Add end bones to transforms + if bone.name.endswith('_end'): + initial_transforms[bone.name] = { + 'head': bone.head.copy(), + 'tail': bone.tail.copy(), + 'roll': bone.roll, + 'matrix': bone.matrix.copy(), + 'parent': bone.parent.name if bone.parent else None + } # Get weighted bones armature.select_set(True) diff --git a/functions/atlas_materials.py b/functions/atlas_materials.py index 48f5c40..86e2c66 100644 --- a/functions/atlas_materials.py +++ b/functions/atlas_materials.py @@ -23,24 +23,24 @@ class MaterialImageList: self.h: int = 0 self.fit = None -def scale_images_to_largest(images: list[Image]) -> set: - x: int = 0 - y: int = 0 +def scale_images_to_largest(images: list[Image]) -> tuple[int, int]: + try: + valid_images = [] + for img in images: + if img and hasattr(img, 'name'): + image_data = bpy.data.images.get(img.name) + if image_data and image_data.has_data: + valid_images.append(image_data) - # Filter out None or invalid images - valid_images = [img for img in images if img and img.has_data] - - if not valid_images: - return 0, 0 + if not valid_images: + return 1, 1 + + max_width = max(img.size[0] for img in valid_images) + max_height = max(img.size[1] for img in valid_images) - for image in valid_images: - x = max(x, image.size[0]) - y = max(y, image.size[1]) - - for image in valid_images: - image.scale(width=int(x), height=int(y)) - - return x, y + return max_width, max_height + except: + return 1, 1 def MaterialImageList_to_Image_list(classitem: MaterialImageList) -> list[Image]: list_of_images: list[Image] = [] @@ -62,56 +62,75 @@ def get_material_images_from_scene(context: Context) -> list[MaterialImageList]: if obj.type == 'MESH': for mat_slot in obj.material_slots: # Only process materials that are selected for atlas - if mat_slot.material and mat_slot.material.include_in_atlas is True: + if mat_slot.material and mat_slot.material.avatar_toolkit.include_in_atlas: new_mat_image_item = MaterialImageList() - try: - new_mat_image_item.albedo = bpy.data.images[mat_slot.material.texture_atlas_albedo] - except Exception: - name = mat_slot.material.name + "_albedo_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.albedo = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.albedo.pixels[:] = numpy.tile(numpy.array([0.0,0.0,0.0,1.0]), 32*32) - try: - new_mat_image_item.normal = bpy.data.images[mat_slot.material.texture_atlas_normal] - except Exception: - name = mat_slot.material.name + "_normal_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.normal = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.normal.pixels[:] = numpy.tile(numpy.array([0.5,0.5,1.0,1.0]), 32*32) - try: - new_mat_image_item.emission = bpy.data.images[mat_slot.material.texture_atlas_emission] - except Exception: - name = mat_slot.material.name + "_emission_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.emission = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.emission.pixels[:] = numpy.tile(numpy.array([0.0,0.0,0.0,1.0]), 32*32) - try: - new_mat_image_item.ambient_occlusion = bpy.data.images[mat_slot.material.texture_atlas_ambient_occlusion] - except Exception: - name = mat_slot.material.name + "_ambient_occlusion_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.ambient_occlusion = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.ambient_occlusion.pixels[:] = numpy.tile(numpy.array([1.0,1.0,1.0,1.0]), 32*32) - try: - new_mat_image_item.height = bpy.data.images[mat_slot.material.texture_atlas_height] - except Exception: - name = mat_slot.material.name + "_height_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.height = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.height.pixels[:] = numpy.tile(numpy.array([0.5,0.5,0.5,1.0]), 32*32) - try: - new_mat_image_item.roughness = bpy.data.images[mat_slot.material.texture_atlas_roughness] - except Exception: - name = mat_slot.material.name + "_roughness_replacement" - if name in bpy.data.images: - bpy.data.images.remove(image=bpy.data.images[name], do_unlink=True) - new_mat_image_item.roughness = bpy.data.images.new(name=name, width=32, height=32, alpha=True) - new_mat_image_item.roughness.pixels[:] = numpy.tile(numpy.array([1.0,1.0,1.0,0.0]), 32*32) + + def get_or_create_image(image_name, replacement_name, default_color): + if image_name and image_name in bpy.data.images: + image = bpy.data.images[image_name] + else: + # Create a new image with the replacement name if it doesn't exist + if replacement_name in bpy.data.images: + image = bpy.data.images[replacement_name] + else: + image = bpy.data.images.new( + name=replacement_name, width=32, height=32, alpha=True + ) + # Set the pixel data to the default color + num_pixels = 32 * 32 + pixel_data = numpy.tile(numpy.array(default_color), num_pixels) + image.pixels[:] = pixel_data + # Set use_fake_user to True to prevent Blender from removing the image + image.use_fake_user = True + return image + + # Albedo + albedo_name = getattr(mat_slot.material, 'texture_atlas_albedo', '') + new_mat_image_item.albedo = get_or_create_image( + albedo_name, + mat_slot.material.name + "_albedo_replacement", + [0.0, 0.0, 0.0, 1.0] + ) + + # Normal + normal_name = getattr(mat_slot.material, 'texture_atlas_normal', '') + new_mat_image_item.normal = get_or_create_image( + normal_name, + mat_slot.material.name + "_normal_replacement", + [0.5, 0.5, 1.0, 1.0] + ) + + # Emission + emission_name = getattr(mat_slot.material, 'texture_atlas_emission', '') + new_mat_image_item.emission = get_or_create_image( + emission_name, + mat_slot.material.name + "_emission_replacement", + [0.0, 0.0, 0.0, 1.0] + ) + + # Ambient Occlusion + ao_name = getattr(mat_slot.material, 'texture_atlas_ambient_occlusion', '') + new_mat_image_item.ambient_occlusion = get_or_create_image( + ao_name, + mat_slot.material.name + "_ambient_occlusion_replacement", + [1.0, 1.0, 1.0, 1.0] + ) + + # Height + height_name = getattr(mat_slot.material, 'texture_atlas_height', '') + new_mat_image_item.height = get_or_create_image( + height_name, + mat_slot.material.name + "_height_replacement", + [0.5, 0.5, 0.5, 1.0] + ) + + # Roughness + roughness_name = getattr(mat_slot.material, 'texture_atlas_roughness', '') + new_mat_image_item.roughness = get_or_create_image( + roughness_name, + mat_slot.material.name + "_roughness_replacement", + [1.0, 1.0, 1.0, 0.0] + ) new_mat_image_item.material = mat_slot.material new_mat_image_item.parent_mesh = obj @@ -120,6 +139,7 @@ def get_material_images_from_scene(context: Context) -> list[MaterialImageList]: return material_image_list + def prep_images_in_scene(context: Context) -> list[MaterialImageList]: preped_images: list[MaterialImageList] = get_material_images_from_scene(context) for MaterialImageClass in preped_images: @@ -135,7 +155,6 @@ def prep_images_in_scene(context: Context) -> list[MaterialImageList]: class AvatarToolKit_OT_AtlasMaterials(Operator): - bl_idname = "avatar_toolkit.atlas_materials" bl_label = t("TextureAtlas.atlas_materials") bl_description = t("TextureAtlas.atlas_materials_desc") @@ -143,12 +162,13 @@ class AvatarToolKit_OT_AtlasMaterials(Operator): @classmethod def poll(cls, context: Context) -> bool: - return context.scene.texture_atlas_Has_Mat_List_Shown + return context.scene.avatar_toolkit.texture_atlas_Has_Mat_List_Shown def execute(self, context: Context) -> set: try: # Get only materials that are explicitly marked for inclusion - selected_materials = [m for m in prep_images_in_scene(context) if m.material and m.material.include_in_atlas is True] + selected_materials = [m for m in prep_images_in_scene(context) + if m.material and m.material.avatar_toolkit.include_in_atlas is True] if not selected_materials: self.report({'WARNING'}, t("TextureAtlas.no_materials_selected")) @@ -157,71 +177,75 @@ class AvatarToolKit_OT_AtlasMaterials(Operator): packer: BinPacker = BinPacker(selected_materials) mat_images = packer.fit() - size: list[int] = [max([matimg.fit.w + matimg.albedo.size[0] for matimg in mat_images]), - max([matimg.fit.h + matimg.albedo.size[1] for matimg in mat_images])] - print([matimg.fit.w + matimg.albedo.size[1] for matimg in mat_images]) + size: list[int] = [ + max([ + matimg.fit.w + matimg.albedo.size[0] + for matimg in mat_images + if matimg.albedo and matimg.albedo.has_data + ] or [1]), + max([ + matimg.fit.h + matimg.albedo.size[1] + for matimg in mat_images + if matimg.albedo and matimg.albedo.has_data + ] or [1]) + ] + print([matimg.fit.w + matimg.albedo.size[0] for matimg in mat_images if matimg.albedo and matimg.albedo.has_data]) atlased_mat: MaterialImageList = MaterialImageList() for mat in mat_images: - x: int = int(mat.fit.x) - y: int = int(mat.fit.y) - w: int = int(mat.albedo.size[0]) - h: int = int(mat.albedo.size[1]) - - for obj in bpy.data.objects: - if obj.type == 'MESH': - mesh: Mesh = obj.data - for layer in mesh.polygons: - if obj.material_slots[layer.material_index].material: - if obj.material_slots[layer.material_index].material == mat.material: - for loop_idx in layer.loop_indices: - layer_loops: MeshUVLoopLayer - for layer_loops in mesh.uv_layers: - uv_item: Float2AttributeValue = layer_loops.uv[loop_idx] - uv_item.vector.x = (uv_item.vector.x*(w/size[0]))+(x/size[0]) - uv_item.vector.y = (uv_item.vector.y*(h/size[1]))+(y/size[1]) - - for type in ["albedo","normal", "emission","ambient_occlusion","height", "roughness"]: - new_image_name: str= "Atlas_"+type+"_"+context.scene.name+"_"+Path(bpy.data.filepath).stem - - print("Processing "+type+" atlas image") - - if new_image_name in bpy.data.images: - bpy.data.images.remove(bpy.data.images[new_image_name]) - - canvas: Image = bpy.data.images.new(name=new_image_name, width=int(size[0]),height=int(size[1]), alpha=True) - c_w = canvas.size[0] - canvas_pixels: list[float] = list(canvas.pixels[:]) - for mat in mat_images: + if mat.albedo and mat.albedo.has_data: x: int = int(mat.fit.x) y: int = int(mat.fit.y) w: int = int(mat.albedo.size[0]) h: int = int(mat.albedo.size[1]) - image_var: Image = eval("mat."+type) - - image_pixels: list[float] = list(image_var.pixels[:]) - - print("writing image \""+image_var.name+"\" to canvas.") - print("x: \""+str(x)+"\" "+"y: \""+str(y)+"\" "+"w: \""+str(w)+"\" "+"h: \""+str(h)+"\" ") - for k in range(0,h): - for i in range(0, w): - for channel in range(0,4): - canvas_pixels[ - int((((k+y)*c_w) - + - (i+x))*4) - +int(channel) - ] = image_pixels[ - int(( - (k*w) - +i)*4) - +int(channel)] + for obj in bpy.data.objects: + if obj.type == 'MESH': + mesh: Mesh = obj.data + for layer in mesh.polygons: + if obj.material_slots[layer.material_index].material: + if obj.material_slots[layer.material_index].material == mat.material: + for loop_idx in layer.loop_indices: + layer_loops: MeshUVLoopLayer + for layer_loops in mesh.uv_layers: + uv_item: Float2AttributeValue = layer_loops.uv[loop_idx] + uv_item.vector.x = (uv_item.vector.x * (w / size[0])) + (x / size[0]) + uv_item.vector.y = (uv_item.vector.y * (h / size[1])) + (y / size[1]) + + for texture_type in ["albedo", "normal", "emission", "ambient_occlusion", "height", "roughness"]: + new_image_name: str = f"Atlas_{texture_type}_{context.scene.name}_{Path(bpy.data.filepath).stem}" + + print(f"Processing {texture_type} atlas image") + + if new_image_name in bpy.data.images: + bpy.data.images.remove(bpy.data.images[new_image_name]) + + canvas: Image = bpy.data.images.new(name=new_image_name, width=int(size[0]), height=int(size[1]), alpha=True) + c_w = canvas.size[0] + canvas_pixels: list[float] = list(canvas.pixels[:]) + for mat in mat_images: + image_var: Image = getattr(mat, texture_type, None) + if image_var and image_var.has_data: + x: int = int(mat.fit.x) + y: int = int(mat.fit.y) + w: int = int(image_var.size[0]) + h: int = int(image_var.size[1]) + + image_pixels: list[float] = list(image_var.pixels[:]) + + print(f"Writing image \"{image_var.name}\" to canvas.") + print(f"x: \"{x}\" y: \"{y}\" w: \"{w}\" h: \"{h}\"") + for k in range(0, h): + for i in range(0, w): + for channel in range(0, 4): + canvas_index = (((k + y) * c_w) + (i + x)) * 4 + channel + image_index = ((k * w) + i) * 4 + channel + canvas_pixels[int(canvas_index)] = image_pixels[int(image_index)] canvas.pixels[:] = canvas_pixels[:] - canvas.save(filepath=os.path.join(os.path.dirname(bpy.data.filepath),new_image_name+".png")) - exec("atlased_mat."+type+" = canvas") + canvas.save(filepath=os.path.join(os.path.dirname(bpy.data.filepath), new_image_name + ".png")) + setattr(atlased_mat, texture_type, canvas) #I am sorry for the amount of nodes I'm instanciating here and their values. #This is so that the nodes look pretty in the UI, which I think looks kinda nice. - @989onan @@ -285,7 +309,7 @@ class AvatarToolKit_OT_AtlasMaterials(Operator): if obj.type == 'MESH': mesh: Mesh = obj.data for i, mat_slot in enumerate(obj.material_slots): - if mat_slot.material and mat_slot.material.include_in_atlas is True: + if mat_slot.material and mat_slot.material.avatar_toolkit.include_in_atlas is True: mesh.materials[i] = atlased_mat.material self.report({'INFO'}, t("TextureAtlas.atlas_completed")) diff --git a/functions/mesh_tools.py b/functions/mesh_tools.py index d3c917f..b9f4fa3 100644 --- a/functions/mesh_tools.py +++ b/functions/mesh_tools.py @@ -51,9 +51,11 @@ class AvatarToolkit_OT_RemoveUnusedShapekeys(bpy.types.Operator): to_delete.append(kb.name) for kb_name in to_delete: - if ("-" in kb_name) or ("=" in kb_name) or ("~" in kb_name): #don't delete category names. - @989onan + if ("-" in kb_name) or ("=" in kb_name) or ("~" in kb_name): continue ob.shape_key_remove(ob.data.shape_keys.key_blocks[kb_name]) + + return {'FINISHED'} class AvatarToolkit_OT_ApplyShapeKey(bpy.types.Operator): diff --git a/functions/mmd_functions.py b/functions/mmd_functions.py index 76ba124..c5bff59 100644 --- a/functions/mmd_functions.py +++ b/functions/mmd_functions.py @@ -302,7 +302,6 @@ def add_principled_shader(material: Material, bake_mmd=True): if material.blend_method != 'OPAQUE': principled_shader.inputs["Alpha"].default_value = material.alpha_threshold material.blend_method = 'CLIP' - material.shadow_method = 'CLIP' def fix_mmd_shader(material: Material): mmd_shader_node = material.node_tree.nodes.get("mmd_shader") diff --git a/functions/translations.py b/functions/translations.py deleted file mode 100644 index 4e03f66..0000000 --- a/functions/translations.py +++ /dev/null @@ -1,97 +0,0 @@ -import os -import json -import bpy -from bpy.app.translations import locale -from typing import Dict, List, Tuple -from ..core.addon_preferences import save_preference, get_preference - -# Use __file__ to get the current file's directory -current_dir = os.path.dirname(os.path.abspath(__file__)) -main_dir = os.path.dirname(current_dir) -resources_dir = os.path.join(main_dir, "resources") -translations_dir = os.path.join(resources_dir, "translations") - -dictionary: Dict[str, str] = dict() -languages: List[str] = [] -verbose: bool = True - -def load_translations() -> bool: - global dictionary, languages - - old_dictionary = dictionary.copy() - - dictionary = dict() - languages = ["auto"] - - # Populate languages list - for i in os.listdir(translations_dir): - lang = i.split(".")[0] - if lang != "auto": - languages.append(lang) - - language_index = get_preference("language", 0) - # print(f"Loading translations for language index: {language_index}") # Debug print - - if language_index == 0: # "auto" - language = bpy.context.preferences.view.language - else: - try: - language = languages[language_index] - except IndexError: - language = bpy.context.preferences.view.language - - # print(f"Selected language: {language}") # Debug print - - translation_file: str = os.path.join(translations_dir, language + ".json") - if os.path.exists(translation_file): - with open(translation_file, 'r', encoding='utf-8') as file: - dictionary = json.load(file)["messages"] - # print(f"Loaded translations: {dictionary}") # Debug print - else: - custom_language: str = language.split("_")[0] - custom_translation_file: str = os.path.join(translations_dir, custom_language + ".json") - if os.path.exists(custom_translation_file): - with open(custom_translation_file, 'r', encoding='utf-8') as file: - dictionary = json.load(file)["messages"] - # print(f"Loaded custom translations: {dictionary}") # Debug print - else: - print(f"Translation file not found for language: {language}") - default_file: str = os.path.join(translations_dir, "en_US.json") - if os.path.exists(default_file): - with open(default_file, 'r', encoding='utf-8') as file: - dictionary = json.load(file)["messages"] - # print(f"Loaded default translations: {dictionary}") # Debug print - else: - print("Default translation file 'en_US.json' not found.") - - return dictionary != old_dictionary - -def t(phrase: str, default: str = None, **kwargs) -> str: - output: str = dictionary.get(phrase) - if output is None: - if verbose: - print(f'Warning: Unknown phrase: {phrase}') - return default if default is not None else phrase - # print(f"Translating '{phrase}' to '{output}'") # Debug print - return output.format(**kwargs) if kwargs else output - -def get_language_display_name(lang: str) -> str: - if lang == "auto": - return t("Language.auto", "Automatic") - return t(f"Language.{lang}", lang) - -def get_languages_list(self, context) -> List[Tuple[str, str, str]]: - return [(str(i), get_language_display_name(lang), f"Use {lang} language") for i, lang in enumerate(languages)] - -def update_language(self, context): - print(f"Updating language to: {self.avatar_toolkit_language}") # Debug print - save_preference("language", int(self.avatar_toolkit_language)) - load_translations() - # Set a flag to indicate that a language change has occurred - context.scene.avatar_toolkit_language_changed = True - # Show popup after language change - bpy.ops.avatar_toolkit.translation_restart_popup('INVOKE_DEFAULT') - -# Initial load of translations -# print("Performing initial load of translations") # Debug print -load_translations() diff --git a/functions/viseme.py b/functions/viseme.py index 6793997..24c3bcb 100644 --- a/functions/viseme.py +++ b/functions/viseme.py @@ -28,16 +28,16 @@ class AvatarToolKit_OT_AutoVisemeButton(bpy.types.Operator): init_progress(context, 5) # 5 main steps update_progress(self, context, t("VisemePanel.start_viseme_creation")) - mesh = bpy.data.objects.get(context.scene.selected_mesh) + mesh = bpy.data.objects.get(context.scene.avatar_toolkit.selected_mesh) if not mesh or not common.has_shapekeys(mesh): raise ValueError(t('AutoVisemeButton.error.noShapekeys')) update_progress(self, context, t("VisemePanel.removing_existing_visemes")) self.remove_existing_vrc_shapekeys(mesh) - shape_a = context.scene.avatar_toolkit_mouth_a - shape_o = context.scene.avatar_toolkit_mouth_o - shape_ch = context.scene.avatar_toolkit_mouth_ch + shape_a = context.scene.avatar_toolkit.mouth_a + shape_o = context.scene.avatar_toolkit.mouth_o + shape_ch = context.scene.avatar_toolkit.mouth_ch if shape_a == "Basis" or shape_o == "Basis" or shape_ch == "Basis": raise ValueError(t('AutoVisemeButton.error.selectShapekeys')) @@ -62,7 +62,7 @@ class AvatarToolKit_OT_AutoVisemeButton(bpy.types.Operator): ] for viseme_name, shape_mix in visemes: - self.create_viseme(mesh, viseme_name, shape_mix, context.scene.avatar_toolkit_shape_intensity) + self.create_viseme(mesh, viseme_name, shape_mix, context.scene.avatar_toolkit.shape_intensity) update_progress(self, context, t("VisemePanel.sorting_shapekeys")) common.sort_shape_keys(mesh)