2025-07-01
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
from typing import cast
|
||||
import bpy
|
||||
|
||||
from ..LIPSYNC2D_Utils import get_package_name
|
||||
|
||||
from ..lipsync_types import BpyContext, BpyObject, BpyPropertyGroup, BpyUILayout
|
||||
|
||||
|
||||
class AnimatorPanelMixin:
|
||||
def __init__(self, obj: BpyObject):
|
||||
|
||||
self.package_name = get_package_name()
|
||||
self.prefs: bpy.types.AddonPreferences | None = None
|
||||
self.obj: BpyObject = obj
|
||||
lipsync_props = self.obj.lipsync2d_props # type: ignore
|
||||
self.props: bpy.types.PropertyGroup = cast(BpyPropertyGroup, lipsync_props)
|
||||
|
||||
if (
|
||||
self.package_name
|
||||
and bpy.context.preferences is not None
|
||||
and self.package_name in bpy.context.preferences.addons
|
||||
):
|
||||
self.prefs = bpy.context.preferences.addons[self.package_name].preferences
|
||||
|
||||
self.current_lang = self.prefs.current_lang if self.prefs is not None else None # type: ignore
|
||||
self.is_model_installed = (
|
||||
True if self.current_lang not in ["", "none"] else False
|
||||
)
|
||||
|
||||
def draw_animation_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw_visemes_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw_animator_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
raise NotImplementedError()
|
||||
|
||||
def draw_edit_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Clean Up:")
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.label(text="Shader Editor:")
|
||||
row = box.row()
|
||||
row.operator("object.remove_lip_sync_node_groups")
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.label(text="Animation:")
|
||||
row = box.row()
|
||||
operator = row.operator("object.remove_lip_sync_animations", text="Remove SK")
|
||||
operator.animation_type = "SHAPEKEYS" # type: ignore
|
||||
operator = row.operator("object.remove_lip_sync_animations", text="Remove SPT")
|
||||
operator.animation_type = "SPRITESHEET" # type: ignore
|
||||
row = box.row()
|
||||
operator = row.operator(
|
||||
"object.remove_lip_sync_animations", text="Remove all Animations"
|
||||
)
|
||||
operator.animation_type = "ALL" # type: ignore
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.prop(self.props, "lip_sync_2d_remove_animation_data")
|
||||
row.prop(self.props, "lip_sync_2d_remove_cgp_node_group")
|
||||
row = box.row()
|
||||
row.alert = True
|
||||
row.operator("object.remove_lip_sync_from_selection")
|
||||
|
||||
def draw_baking_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
if not self.is_model_installed:
|
||||
new_row = layout.row()
|
||||
new_row.label(
|
||||
text="Select a Language Model before Analyzing audio",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
|
||||
new_row = layout.row()
|
||||
new_row.operator(
|
||||
"sound.cgp_analyze_audio", text="Bake audio", icon="SCRIPTPLUGINS"
|
||||
)
|
||||
new_row.enabled = self.is_model_installed
|
||||
|
||||
def draw_bake_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_head, panel_body = layout.panel(
|
||||
"cgp_lipsync_bake_settings_dropdown", default_closed=True
|
||||
)
|
||||
panel_head.label(text="Bake Settings")
|
||||
|
||||
if panel_body is not None:
|
||||
row = panel_body.row()
|
||||
row.label(text="Misc:")
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_use_clear_keyframes")
|
||||
row = panel_body.row()
|
||||
row.label(text="Range:")
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_use_bake_range")
|
||||
row = panel_body.row(align=True)
|
||||
row.prop(self.props, "lip_sync_2d_bake_start", text="Start")
|
||||
row.prop(self.props, "lip_sync_2d_bake_end", text="End")
|
||||
row.enabled = self.props.lip_sync_2d_use_bake_range # type: ignore
|
||||
@@ -0,0 +1,117 @@
|
||||
import bpy
|
||||
|
||||
from ..lipsync_types import BpyObject
|
||||
from .AnimatorPanelMixin import AnimatorPanelMixin
|
||||
from ..Core.phoneme_to_viseme import viseme_items_mpeg4_v2 as viseme_items
|
||||
from ..lipsync_types import BpyContext, BpyUILayout
|
||||
|
||||
|
||||
class AnimatorPanelPoseAssetsStrategy(AnimatorPanelMixin):
|
||||
def __init__(self, obj: BpyObject):
|
||||
super().__init__(obj)
|
||||
if not isinstance(obj.data, bpy.types.Mesh):
|
||||
return
|
||||
|
||||
def draw_animator_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_header, panel_body = layout.panel(
|
||||
"vpg_lipsync_animator_dropdown", default_closed=True
|
||||
)
|
||||
|
||||
panel_header.label(text="Rig Settings")
|
||||
|
||||
if panel_body is not None:
|
||||
row = panel_body.row()
|
||||
row.label(text="Rig Type")
|
||||
|
||||
row = panel_body.row(align=True)
|
||||
row.prop(self.props, "lip_sync_2d_rig_type_basic", toggle=True)
|
||||
row.prop(self.props, "lip_sync_2d_rig_type_advanced", toggle=True)
|
||||
panel_body.separator(factor=1)
|
||||
|
||||
def draw_animation_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_header, panel_body = layout.panel(
|
||||
"cgp_lipsync_animation_dropdown", default_closed=False
|
||||
)
|
||||
panel_header.label(text="Animation Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row()
|
||||
row.label(text="Motion:")
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_close_motion_duration")
|
||||
|
||||
self.draw_thresholds(self.props, panel_body)
|
||||
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_prioritize_accuracy", toggle=True)
|
||||
|
||||
def draw_visemes_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_head, panel_body = layout.panel(
|
||||
"cgp_lipsync_viseme_dropdown", default_closed=False
|
||||
)
|
||||
panel_head.label(text="Viseme Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text="Viseme")
|
||||
row.label(text="Pose")
|
||||
|
||||
visemes = viseme_items(None, None)
|
||||
|
||||
for i, viseme in enumerate(visemes):
|
||||
lang_code = list(viseme)[0]
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text=f"{lang_code}")
|
||||
row.prop(self.props, f"lip_sync_2d_viseme_pose_{lang_code}", text="")
|
||||
|
||||
def draw_thresholds(self, props, layout):
|
||||
row = layout.row()
|
||||
row.label(text="Thresholds:")
|
||||
data_list = ["lip_sync_2d_in_between_threshold", "lip_sync_2d_sil_threshold"]
|
||||
row = layout.row()
|
||||
for data in data_list:
|
||||
row.prop(props, data)
|
||||
|
||||
def draw_baking_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
if not self.is_model_installed:
|
||||
new_row = layout.row()
|
||||
new_row.label(
|
||||
text="Select a Language Model before Analyzing audio",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
|
||||
new_row = layout.row()
|
||||
new_row.operator(
|
||||
"sound.cgp_analyze_audio", text="Bake audio", icon="SCRIPTPLUGINS"
|
||||
)
|
||||
new_row.enabled = self.is_model_installed
|
||||
|
||||
def draw_edit_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Pose Assets:")
|
||||
box = layout.box()
|
||||
row = box.row(align=True)
|
||||
row.operator("lipsync2d.refresh_pose_assets")
|
||||
|
||||
row = layout.row()
|
||||
row.label(text="Clean Up:")
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.label(text="Animation:")
|
||||
row = box.row()
|
||||
operator = row.operator(
|
||||
"object.remove_lip_sync_animations", text="Remove Pose Animation"
|
||||
)
|
||||
operator.animation_type = "POSEASSETS" # type: ignore
|
||||
row = box.row()
|
||||
operator = row.operator(
|
||||
"object.remove_lip_sync_animations", text="Remove all Animations"
|
||||
)
|
||||
operator.animation_type = "ALL" # type: ignore
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.prop(self.props, "lip_sync_2d_remove_animation_data")
|
||||
row = box.row()
|
||||
row.alert = True
|
||||
row.operator("object.remove_lip_sync_from_selection")
|
||||
@@ -0,0 +1,100 @@
|
||||
import bpy
|
||||
|
||||
from ..lipsync_types import BpyObject
|
||||
from .AnimatorPanelMixin import AnimatorPanelMixin
|
||||
from ..Core.phoneme_to_viseme import viseme_items_mpeg4_v2 as viseme_items
|
||||
from ..lipsync_types import BpyContext, BpyUILayout
|
||||
|
||||
|
||||
class AnimatorPanelShapeKeysStrategy(AnimatorPanelMixin):
|
||||
def __init__(self, obj: BpyObject):
|
||||
super().__init__(obj)
|
||||
if not isinstance(obj.data, bpy.types.Mesh):
|
||||
return
|
||||
|
||||
self.at_least_two_shape_keys = bool(
|
||||
(
|
||||
obj.data
|
||||
and obj.data.shape_keys
|
||||
and obj.data.shape_keys.key_blocks.__len__() > 1
|
||||
)
|
||||
)
|
||||
|
||||
self.is_relative = bool(
|
||||
(obj.data and obj.data.shape_keys and obj.data.shape_keys.use_relative)
|
||||
)
|
||||
|
||||
def draw_animator_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_animation_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_header, panel_body = layout.panel(
|
||||
"cgp_lipsync_animation_dropdown", default_closed=False
|
||||
)
|
||||
panel_header.label(text="Animation Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row()
|
||||
row.label(text="Motion:")
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_close_motion_duration")
|
||||
|
||||
self.draw_thresholds(self.props, panel_body)
|
||||
|
||||
def draw_visemes_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_head, panel_body = layout.panel(
|
||||
"cgp_lipsync_viseme_dropdown", default_closed=True
|
||||
)
|
||||
panel_head.label(text="Viseme Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text="Viseme")
|
||||
row.label(text="Shape Key")
|
||||
|
||||
visemes = viseme_items(None, None)
|
||||
|
||||
for i, viseme in enumerate(visemes):
|
||||
lang_code = list(viseme)[0]
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text=f"{lang_code}")
|
||||
row.prop(
|
||||
self.props, f"lip_sync_2d_viseme_shape_keys_{lang_code}", text=""
|
||||
)
|
||||
|
||||
def draw_thresholds(self, props, layout):
|
||||
row = layout.row()
|
||||
row.label(text="Thresholds:")
|
||||
data_list = ["lip_sync_2d_in_between_threshold", "lip_sync_2d_sil_threshold"]
|
||||
row = layout.row()
|
||||
for data in data_list:
|
||||
row.prop(props, data)
|
||||
|
||||
def draw_baking_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
if not self.is_model_installed:
|
||||
new_row = layout.row()
|
||||
new_row.label(
|
||||
text="Select a Language Model before Analyzing audio",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
if not self.at_least_two_shape_keys:
|
||||
new_row = layout.row()
|
||||
new_row.label(
|
||||
text="Missing Shape Keys",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
|
||||
if not self.is_relative:
|
||||
new_row = layout.row()
|
||||
new_row.label(
|
||||
text="Shape Keys have to be set to 'Relative'",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
|
||||
new_row = layout.row()
|
||||
new_row.operator(
|
||||
"sound.cgp_analyze_audio", text="Bake audio", icon="SCRIPTPLUGINS"
|
||||
)
|
||||
new_row.enabled = (
|
||||
self.is_model_installed
|
||||
and self.at_least_two_shape_keys
|
||||
and self.is_relative
|
||||
)
|
||||
@@ -0,0 +1,101 @@
|
||||
from .AnimatorPanelMixin import AnimatorPanelMixin
|
||||
from ..Core.phoneme_to_viseme import viseme_items_mpeg4_v2 as viseme_items
|
||||
from ..lipsync_types import BpyContext, BpyUILayout
|
||||
|
||||
|
||||
class AnimatorPanelSpriteSheetStrategy(AnimatorPanelMixin):
|
||||
def draw_animator_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_header, panel_body = layout.panel(
|
||||
"cgp_lipsync_animator_dropdown", default_closed=False
|
||||
)
|
||||
panel_header.label(text="Sprite Sheet Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row()
|
||||
row.label(text="Area")
|
||||
|
||||
row = panel_body.row()
|
||||
row.label(
|
||||
text="Go in Edit Mode to define Mouth Area",
|
||||
icon="INFO_LARGE",
|
||||
)
|
||||
|
||||
row = panel_body.row()
|
||||
row.operator("mesh.set_lips_area", text="Set Mouth Area")
|
||||
panel_body.separator(factor=1)
|
||||
|
||||
row = panel_body.row()
|
||||
row.label(text="Select your Sprite sheet")
|
||||
panel_body.template_ID_preview(
|
||||
self.props,
|
||||
"lip_sync_2d_sprite_sheet",
|
||||
rows=2,
|
||||
cols=6,
|
||||
open="image.open",
|
||||
)
|
||||
|
||||
panel_body.separator(factor=1)
|
||||
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text="Spritesheet Format")
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_format", text="")
|
||||
|
||||
panel_body.separator(factor=1)
|
||||
|
||||
row = panel_body.row(align=True)
|
||||
if self.props["lip_sync_2d_sprite_sheet_format"] == 3:
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_rows")
|
||||
elif self.props["lip_sync_2d_sprite_sheet_format"] == 2:
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_columns")
|
||||
elif self.props["lip_sync_2d_sprite_sheet_format"] == 0:
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_rows")
|
||||
elif self.props["lip_sync_2d_sprite_sheet_format"] == 1:
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_columns")
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_rows")
|
||||
|
||||
row = panel_body.row()
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_index")
|
||||
|
||||
panel_body.separator(factor=1)
|
||||
|
||||
row = panel_body.row()
|
||||
row.label(text="Scale")
|
||||
row = panel_body.row(align=True)
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_sprite_scale")
|
||||
row.prop(self.props, "lip_sync_2d_sprite_sheet_main_scale", text="Main")
|
||||
|
||||
def draw_animation_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_header, panel_body = layout.panel(
|
||||
"cgp_lipsync_animation_dropdown", default_closed=True
|
||||
)
|
||||
panel_header.label(text="Animation Settings")
|
||||
if panel_body is not None:
|
||||
self.draw_thresholds(self.props, panel_body)
|
||||
|
||||
def draw_visemes_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
panel_head, panel_body = layout.panel(
|
||||
"cgp_lipsync_viseme_dropdown", default_closed=True
|
||||
)
|
||||
panel_head.label(text="Viseme Settings")
|
||||
if panel_body is not None:
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text="Viseme")
|
||||
row.label(text="Image index")
|
||||
|
||||
visemes = viseme_items(None, None)
|
||||
|
||||
for i, viseme in enumerate(visemes):
|
||||
lang_code = list(viseme)[0]
|
||||
row = panel_body.row(align=True)
|
||||
row.label(text=f"{lang_code}")
|
||||
row.prop(self.props, f"lip_sync_2d_viseme_{lang_code}", text="")
|
||||
|
||||
def draw_thresholds(self, props, layout):
|
||||
row = layout.row()
|
||||
row.label(text="Thresholds:")
|
||||
data_list = [
|
||||
"lip_sync_2d_sps_in_between_threshold",
|
||||
"lip_sync_2d_sps_sil_threshold",
|
||||
]
|
||||
row = layout.row()
|
||||
for data in data_list:
|
||||
row.prop(props, data)
|
||||
@@ -0,0 +1,68 @@
|
||||
import bpy
|
||||
|
||||
from .AnimatorPanelPoseAssetsStrategy import AnimatorPanelPoseAssetsStrategy
|
||||
|
||||
from .protocols import LIPSYNC2D_AnimatorPanel
|
||||
from ..Panels.AnimatorPanelShapeKeysStrategy import AnimatorPanelShapeKeysStrategy
|
||||
from ..Panels.AnimatorPanelSpriteSheetStrategy import AnimatorPanelSpriteSheetStrategy
|
||||
|
||||
|
||||
class LIPSYNC2D_PT_Edit(bpy.types.Panel):
|
||||
bl_idname = "LIPSYNC2D_PT_Edit"
|
||||
bl_label = "Quick Edit"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "Lip Sync"
|
||||
bl_options = {"DEFAULT_CLOSED"}
|
||||
|
||||
def __init__(self, *args, **kargs):
|
||||
super().__init__(*args, **kargs)
|
||||
|
||||
self.animator_panel: LIPSYNC2D_AnimatorPanel | None = None
|
||||
|
||||
def draw(self, context: bpy.types.Context):
|
||||
if self.layout is None:
|
||||
return
|
||||
if context.scene is None:
|
||||
return
|
||||
if context.preferences is None:
|
||||
return
|
||||
|
||||
active_obj = context.active_object
|
||||
|
||||
if active_obj is None or (
|
||||
active_obj.type != "MESH" and active_obj.type != "ARMATURE"
|
||||
):
|
||||
self.layout.label(
|
||||
text="Please, select an Object with Mesh Data or an Armature",
|
||||
icon="INFO_LARGE",
|
||||
)
|
||||
return
|
||||
|
||||
if not hasattr(active_obj, "lipsync2d_props"):
|
||||
self.layout.label(
|
||||
text="Something wrong happened. Try uninstall / reinstall Lip Sync Addon",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
return
|
||||
|
||||
if "lip_sync_2d_initialized" not in context.active_object.lipsync2d_props: # type: ignore
|
||||
self.layout.label(text="Press on Add Lip Sync to start", icon="INFO_LARGE")
|
||||
return
|
||||
|
||||
props = active_obj.lipsync2d_props # type: ignore
|
||||
|
||||
if props is None:
|
||||
return
|
||||
|
||||
if props.lip_sync_2d_lips_type == "SHAPEKEYS":
|
||||
self.animator_panel = AnimatorPanelShapeKeysStrategy(active_obj)
|
||||
elif props.lip_sync_2d_lips_type == "SPRITESHEET":
|
||||
self.animator_panel = AnimatorPanelSpriteSheetStrategy(active_obj)
|
||||
elif props.lip_sync_2d_lips_type == "POSEASSETS":
|
||||
self.animator_panel = AnimatorPanelPoseAssetsStrategy(active_obj)
|
||||
|
||||
if self.animator_panel is None:
|
||||
return
|
||||
|
||||
self.animator_panel.draw_edit_section(context, self.layout)
|
||||
@@ -0,0 +1,90 @@
|
||||
import bpy
|
||||
|
||||
from .AnimatorPanelPoseAssetsStrategy import AnimatorPanelPoseAssetsStrategy
|
||||
|
||||
from .protocols import LIPSYNC2D_AnimatorPanel
|
||||
|
||||
from .AnimatorPanelSpriteSheetStrategy import AnimatorPanelSpriteSheetStrategy
|
||||
|
||||
from .AnimatorPanelShapeKeysStrategy import AnimatorPanelShapeKeysStrategy
|
||||
|
||||
|
||||
class LIPSYNC2D_PT_Panel(bpy.types.Panel):
|
||||
"""Creates a Panel in the scene context of the property editor"""
|
||||
|
||||
bl_label = "Lip Sync"
|
||||
bl_idname = "LIPSYNC2D_PT_Panel"
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "Lip Sync"
|
||||
|
||||
def __init__(self, *args, **kargs) -> None:
|
||||
super().__init__(*args, **kargs)
|
||||
|
||||
self.animator_panel: LIPSYNC2D_AnimatorPanel | None = None
|
||||
|
||||
def draw(self, context: bpy.types.Context):
|
||||
if self.layout is None:
|
||||
return
|
||||
if context.scene is None:
|
||||
return
|
||||
if context.preferences is None:
|
||||
return
|
||||
|
||||
active_obj = context.active_object
|
||||
|
||||
if active_obj is None or (
|
||||
active_obj.type != "MESH" and active_obj.type != "ARMATURE"
|
||||
):
|
||||
self.layout.label(
|
||||
text="Please, select an Object with Mesh Data or an Armature",
|
||||
icon="INFO_LARGE",
|
||||
)
|
||||
return
|
||||
|
||||
if not hasattr(active_obj, "lipsync2d_props"):
|
||||
self.layout.label(
|
||||
text="Something wrong happened. Try uninstall / reinstall Lip Sync Addon",
|
||||
icon="WARNING_LARGE",
|
||||
)
|
||||
return
|
||||
|
||||
props = active_obj.lipsync2d_props # type: ignore
|
||||
|
||||
if props is None:
|
||||
return
|
||||
|
||||
if props.lip_sync_2d_lips_type == "SHAPEKEYS":
|
||||
self.animator_panel = AnimatorPanelShapeKeysStrategy(active_obj)
|
||||
elif props.lip_sync_2d_lips_type == "SPRITESHEET":
|
||||
self.animator_panel = AnimatorPanelSpriteSheetStrategy(active_obj)
|
||||
elif props.lip_sync_2d_lips_type == "POSEASSETS":
|
||||
self.animator_panel = AnimatorPanelPoseAssetsStrategy(active_obj)
|
||||
|
||||
layout = self.layout
|
||||
|
||||
if (
|
||||
context.active_object is None
|
||||
or not hasattr(context.active_object, "lipsync2d_props")
|
||||
or context.active_object.lipsync2d_props.lip_sync_2d_initialized == False # type: ignore
|
||||
):
|
||||
row = layout.row(align=True)
|
||||
row.operator(
|
||||
"object.set_lipsync_custom_properties", text="Add Lip Sync on Selection"
|
||||
)
|
||||
return
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.label(text="Animation type")
|
||||
row.prop(props, "lip_sync_2d_lips_type", text="")
|
||||
|
||||
if self.animator_panel is None:
|
||||
return
|
||||
|
||||
layout.separator()
|
||||
self.animator_panel.draw_animator_section(context, layout)
|
||||
self.animator_panel.draw_visemes_section(context, layout)
|
||||
self.animator_panel.draw_animation_section(context, layout)
|
||||
self.animator_panel.draw_bake_section(context, layout)
|
||||
layout.separator()
|
||||
self.animator_panel.draw_baking_section(context, layout)
|
||||
@@ -0,0 +1,32 @@
|
||||
import platform
|
||||
|
||||
import bpy
|
||||
|
||||
from ..LIPSYNC2D_Utils import get_package_name
|
||||
from ..Preferences.LIPSYNC2D_AP_Preferences import LIPSYNC2D_AP_Preferences
|
||||
|
||||
|
||||
class LIPSYNC2D_PT_Settings(bpy.types.Panel):
|
||||
bl_idname="LIPSYNC2D_PT_Settings"
|
||||
bl_label="Quick Setup"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = 'Lip Sync'
|
||||
|
||||
platform = platform.system()
|
||||
|
||||
def draw(self, context: bpy.types.Context):
|
||||
layout = self.layout
|
||||
prefs = context.preferences.addons[get_package_name()].preferences # type: ignore
|
||||
if not layout or prefs is None:
|
||||
return
|
||||
|
||||
self.draw_espeak_model_settings(layout, prefs)
|
||||
|
||||
def draw_espeak_model_settings(self, layout: bpy.types.UILayout, prefs: bpy.types.AddonPreferences):
|
||||
LIPSYNC2D_AP_Preferences.draw_online_access_warning(layout)
|
||||
row = layout.row()
|
||||
row.label(text="Language Model")
|
||||
row.prop(prefs, "current_lang", text="")
|
||||
LIPSYNC2D_AP_Preferences.draw_model_state(row) #type: ignore
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
from typing import Protocol
|
||||
|
||||
from ..lipsync_types import BpyContext, BpyUILayout
|
||||
|
||||
|
||||
class LIPSYNC2D_AnimatorPanel(Protocol):
|
||||
def draw_animation_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_visemes_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_edit_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_baking_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_animator_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
|
||||
def draw_bake_section(self, context: BpyContext, layout: BpyUILayout):
|
||||
pass
|
||||
Reference in New Issue
Block a user