131 lines
5.1 KiB
Python
131 lines
5.1 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import bpy
|
|
from utilities.constants import MMD_VISEME_COUNT
|
|
from utilities.functions import MMD_JP_MAPPING, VRC_ORDER, build_viseme_map
|
|
|
|
|
|
def viseme_enum_items(self, context):
|
|
vmap = build_viseme_map('_', '_', '_')
|
|
items = [(k, k, '') for k in vmap.keys()]
|
|
items.append(('vrc.blink', 'vrc.blink', ''))
|
|
return items
|
|
|
|
|
|
class VRCVIS_PT_Panel(bpy.types.Panel):
|
|
bl_idname = 'VIEW3D_PT_visemes_converter'
|
|
bl_label = 'Visemes Converter'
|
|
bl_space_type = 'VIEW_3D'
|
|
bl_region_type = 'UI'
|
|
bl_category = 'Visemes Tool'
|
|
|
|
def draw(self, context):
|
|
layout = self.layout
|
|
scene = context.scene
|
|
|
|
box = layout.box()
|
|
box.label(text='Mesh', icon='MESH_DATA')
|
|
mesh_objects = [o for o in bpy.data.objects if o.type == 'MESH' and o.data.shape_keys]
|
|
if not mesh_objects:
|
|
box.label(text='Nessuna mesh con shape key', icon='ERROR')
|
|
return
|
|
box.prop_search(scene, 'vrcvis_mesh', bpy.data, 'objects', text='')
|
|
|
|
mesh_name = scene.vrcvis_mesh
|
|
if not mesh_name or mesh_name not in bpy.data.objects:
|
|
layout.label(text='Seleziona una mesh', icon='INFO')
|
|
return
|
|
obj = bpy.data.objects[mesh_name]
|
|
if obj.type != 'MESH' or not obj.data.shape_keys:
|
|
layout.label(text='Mesh senza shape key', icon='ERROR')
|
|
return
|
|
|
|
layout.separator(factor=0.3)
|
|
box2 = layout.box()
|
|
box2.label(text='VRChat Visemes (MMD → vrc.*)', icon='SHAPEKEY_DATA')
|
|
|
|
row = box2.row()
|
|
row.operator('vrc_viseme.auto_detect', icon='VIEWZOOM', text='Auto-rileva (MMD → VRC)')
|
|
box2.separator(factor=0.5)
|
|
|
|
row = box2.row(align=True)
|
|
row.label(text='A (あ):')
|
|
row.prop_search(scene, 'vrcvis_mouth_a', obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
row = box2.row(align=True)
|
|
row.label(text='O (お):')
|
|
row.prop_search(scene, 'vrcvis_mouth_o', obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
row = box2.row(align=True)
|
|
row.label(text='CH (い):')
|
|
row.prop_search(scene, 'vrcvis_mouth_ch', obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
row = box2.row(align=True)
|
|
row.label(text='Blink:')
|
|
row.prop_search(scene, 'vrcvis_blink', obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
box2.separator(factor=0.5)
|
|
box2.prop(scene, 'vrcvis_intensity', text='Intensità')
|
|
box2.prop(scene, 'vrcvis_overwrite', text='Sovrascrivi esistenti')
|
|
|
|
box2.separator(factor=0.5)
|
|
row = box2.row(align=True)
|
|
row.scale_y = 1.2
|
|
if scene.vrcvis_preview_active:
|
|
row.operator('vrc_viseme.preview', text='Stop Preview', icon='PAUSE')
|
|
row2 = box2.row(align=True)
|
|
row2.prop(scene, 'vrcvis_preview_viseme', text='')
|
|
row2.operator('vrc_viseme.update_preview', text='', icon='FILE_REFRESH')
|
|
else:
|
|
row.operator('vrc_viseme.preview', text='Preview Viseme', icon='PLAY')
|
|
|
|
box2.separator(factor=0.5)
|
|
row = box2.row(align=True)
|
|
row.scale_y = 1.4
|
|
row.operator('vrc_viseme.generate', icon='TRIA_RIGHT')
|
|
|
|
row2 = box2.row(align=True)
|
|
row2.operator('vrc_viseme.reorder', icon='SORTSIZE')
|
|
row2.operator('vrc_viseme.remove_all', icon='X')
|
|
|
|
if obj.data.shape_keys:
|
|
existing_vrc = [k.name for k in obj.data.shape_keys.key_blocks if k.name.startswith('vrc.')]
|
|
if existing_vrc:
|
|
total = len(VRC_ORDER)
|
|
box5 = box2.box()
|
|
box5.label(text=f'{len(existing_vrc)}/{total} vrc.* presenti', icon='CHECKMARK')
|
|
col = box5.column(align=True)
|
|
for name in VRC_ORDER:
|
|
r = col.row(align=True)
|
|
r.label(text=name, icon='CHECKBOX_HLT' if name in existing_vrc else 'CHECKBOX_DEHLT')
|
|
|
|
layout.separator(factor=0.3)
|
|
box_mmd = layout.box()
|
|
box_mmd.label(text='Converti in MMD (EN/VRC → JP)', icon='FILE_REFRESH')
|
|
|
|
row = box_mmd.row()
|
|
row.operator('vrc_viseme.mmd_auto_detect', icon='VIEWZOOM', text='Auto-rileva (EN → JP)')
|
|
|
|
box_mmd.separator(factor=0.4)
|
|
box_mmd.label(text='--- MMD Visemes ---', icon='SHAPEKEY_DATA')
|
|
for _jp, suffix, en_label, _ in MMD_JP_MAPPING[:MMD_VISEME_COUNT]:
|
|
row = box_mmd.row(align=True)
|
|
row.label(text=en_label + ':')
|
|
row.prop_search(scene, f'vrcvis_mmd_{suffix}',
|
|
obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
box_mmd.separator(factor=0.4)
|
|
box_mmd.label(text='--- Altre forme ---', icon='SHAPEKEY_DATA')
|
|
for _jp, suffix, en_label, _ in MMD_JP_MAPPING[MMD_VISEME_COUNT:]:
|
|
row = box_mmd.row(align=True)
|
|
row.label(text=en_label + ':')
|
|
row.prop_search(scene, f'vrcvis_mmd_{suffix}',
|
|
obj.data.shape_keys, 'key_blocks', text='')
|
|
|
|
box_mmd.separator(factor=0.5)
|
|
row = box_mmd.row(align=True)
|
|
row.scale_y = 1.4
|
|
row.operator('vrc_viseme.mmd_convert', icon='DUPLICATE')
|
|
row.operator('vrc_viseme.mmd_remove', icon='X')
|