531 lines
21 KiB
C#
531 lines
21 KiB
C#
/*
|
|
* RsiWriter.cs
|
|
* Copyright (c) 2007-2009 kbinani
|
|
*
|
|
* This file is part of LipSync.
|
|
*
|
|
* LipSync is free software; you can redistribute it and/or
|
|
* modify it under the terms of the BSD License.
|
|
*
|
|
* LipSync is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
*/
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Xml;
|
|
|
|
using Boare.Lib.AppUtil;
|
|
|
|
namespace LipSync {
|
|
|
|
public class RsiWriter {
|
|
#region Constant String
|
|
static readonly string[] mouth_set = new string[]{
|
|
"a",
|
|
"aa",
|
|
"i",
|
|
"u",
|
|
"e",
|
|
"o",
|
|
"xo",
|
|
"nn"
|
|
};
|
|
static readonly string[] mouth_set_ja = new string[]{
|
|
"あ",
|
|
"ああ",
|
|
"い",
|
|
"う",
|
|
"え",
|
|
"お",
|
|
"ぉ",
|
|
"ん"
|
|
}; // mouth_setと同順で対応して無いとNG
|
|
static readonly string[] dict_text = new string[]{
|
|
"あ,a",
|
|
"か,a",
|
|
"が,a",
|
|
"さ,a",
|
|
"ざ,a",
|
|
"た,a",
|
|
"だ,a",
|
|
"な,a",
|
|
"は,a",
|
|
"ば,a",
|
|
"ぱ,a",
|
|
"ま,a",
|
|
"や,a",
|
|
"ら,a",
|
|
"わ,a",
|
|
"い,i",
|
|
"き,i",
|
|
"ぎ,i",
|
|
"し,i",
|
|
"じ,i",
|
|
"ち,i",
|
|
"ぢ,i",
|
|
"に,i",
|
|
"ひ,i",
|
|
"び,i",
|
|
"ぴ,i",
|
|
"み,i",
|
|
"り,i",
|
|
"う,u",
|
|
"く,u",
|
|
"ぐ,u",
|
|
"す,u",
|
|
"ず,u",
|
|
"つ,u",
|
|
"づ,u",
|
|
"ぬ,u",
|
|
"ふ,u",
|
|
"ぶ,u",
|
|
"む,u",
|
|
"ゆ,u",
|
|
"る,u",
|
|
"え,e",
|
|
"け,e",
|
|
"げ,e",
|
|
"せ,e",
|
|
"ぜ,e",
|
|
"て,e",
|
|
"で,e",
|
|
"ね,e",
|
|
"へ,e",
|
|
"べ,e",
|
|
"め,e",
|
|
"れ,e",
|
|
"お,o",
|
|
"こ,o",
|
|
"ご,o",
|
|
"そ,o",
|
|
"ぞ,o",
|
|
"と,o",
|
|
"ど,o",
|
|
"の,o",
|
|
"ほ,o",
|
|
"ぼ,o",
|
|
"ぽ,o",
|
|
"も,o",
|
|
"よ,o",
|
|
"ろ,o",
|
|
"を,xo",
|
|
"ん,nn"
|
|
};
|
|
static readonly string[] dict_symbol = new string[]{
|
|
"a,a",
|
|
"i,i",
|
|
"M,u",
|
|
"e,e",
|
|
"o,o",
|
|
"k,xo",
|
|
"k',i",
|
|
"g,e",
|
|
"g',i",
|
|
"s,a",
|
|
"S,i",
|
|
"z,u",
|
|
"Z,i",
|
|
"dz,u",
|
|
"dZ,i",
|
|
"t,e",
|
|
"t',i",
|
|
"ts,u",
|
|
"tS,i",
|
|
"d,a",
|
|
"d',i",
|
|
"n,a",
|
|
"J,i",
|
|
"h,a",
|
|
@"h\,xo",
|
|
"C,i",
|
|
@"p\,u",
|
|
@"p\',i",
|
|
"b,o",
|
|
"b',i",
|
|
"p,o",
|
|
"p',i",
|
|
"m,a",
|
|
"m',i",
|
|
"j,u",
|
|
"4,aa",
|
|
"4',i",
|
|
"w,a",
|
|
@"N\,nn"
|
|
};
|
|
#endregion
|
|
|
|
public static string _( string s ) {
|
|
return Messaging.GetMessage( s );
|
|
}
|
|
|
|
/// <summary>
|
|
/// a, aa, i, u, e, o, xo, nnを、あ・ああ・い・う・え・お・ぉ・んに変換します。それ以外は""を返す
|
|
/// </summary>
|
|
/// <param name="symbol"></param>
|
|
/// <returns></returns>
|
|
private static string Translate( string symbol ) {
|
|
for ( int i = 0; i < mouth_set.Length; i++ ) {
|
|
if ( mouth_set[i] == symbol ) {
|
|
return mouth_set_ja[i];
|
|
}
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 与えられたタイトルの画像が口パク用の基本画像セットの物かどうかを判定します
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
private static bool IsImageNameForMouth( string name ) {
|
|
foreach ( string s in mouth_set ) {
|
|
if ( s == name ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
public static void Write( Character3 character, string fpath ) {
|
|
string image_folder_name = Path.GetFileNameWithoutExtension( fpath );
|
|
string image_folder = Path.Combine( Path.GetDirectoryName( fpath ), image_folder_name );
|
|
if ( Directory.Exists( image_folder ) ) {
|
|
DialogResult res = MessageBox.Show(
|
|
_( "Image directory already exists. Would you like to overwrite them?" ),
|
|
_( "warning" ),
|
|
MessageBoxButtons.YesNoCancel,
|
|
MessageBoxIcon.Exclamation,
|
|
MessageBoxDefaultButton.Button2 );
|
|
if ( res == DialogResult.No ) {
|
|
using ( OpenFileDialog dlg = new OpenFileDialog() ) {
|
|
dlg.FileName = Path.GetDirectoryName( fpath );
|
|
if ( dlg.ShowDialog() == DialogResult.OK ) {
|
|
image_folder = dlg.FileName;
|
|
image_folder_name = Path.GetFileName( image_folder );
|
|
} else {
|
|
return;
|
|
}
|
|
}
|
|
} else if ( res == DialogResult.Cancel ) {
|
|
return;
|
|
}
|
|
} else {
|
|
Directory.CreateDirectory( image_folder );
|
|
}
|
|
#if DEBUG
|
|
Common.DebugWriteLine( "image_folder_name=" + image_folder_name );
|
|
Common.DebugWriteLine( "image_folder=" + image_folder );
|
|
#endif
|
|
XmlTextWriter doc = new XmlTextWriter( fpath, Encoding.UTF8 );
|
|
doc.Formatting = Formatting.Indented;
|
|
doc.Indentation = 2;
|
|
doc.IndentChar = ' ';
|
|
|
|
// タグが未指定な物のgroup名を決めておく
|
|
string group_name_for_empty = "Another";
|
|
bool found = true;
|
|
int count = 0;
|
|
while ( found ) {
|
|
found = false;
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( img.tag == group_name_for_empty ) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( found ) {
|
|
count++;
|
|
group_name_for_empty = "Another" + count;
|
|
}
|
|
}
|
|
|
|
doc.WriteStartElement( "SingerConfig" );
|
|
{
|
|
doc.WriteElementString( "Title", character.Name );
|
|
doc.WriteElementString( "Size", character.Size.Width + "," + character.Size.Height );
|
|
doc.WriteElementString( "RootImageName", "root" );
|
|
List<string> sets = new List<string>(); // root以下のsetのリスト
|
|
|
|
#region "SingerConfig/Images"
|
|
doc.WriteStartElement( "Images" );
|
|
{
|
|
// トリガー込み
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( IsImageNameForMouth( img.title ) ) {
|
|
continue;
|
|
}
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "center", (-img.XOffset) + ", " + (-img.YOffset) );
|
|
doc.WriteAttributeString( "name", img.title );
|
|
doc.WriteAttributeString( "size", img.Image.Width + ", " + img.Image.Height );
|
|
string img_fname = img.title + ".png";
|
|
img.Image.Save( Path.Combine( image_folder, img_fname ), System.Drawing.Imaging.ImageFormat.Png );
|
|
doc.WriteAttributeString( "path", image_folder_name + "/" + img_fname );
|
|
doc.WriteAttributeString( "trigger", img.title );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
// 基本口画像。トリガー指定の無い奴も出力しないといけない?(未確認
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( !IsImageNameForMouth( img.title ) ) {
|
|
continue;
|
|
}
|
|
|
|
// 自動用
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "center", (-img.XOffset) + ", " + (-img.YOffset) );
|
|
doc.WriteAttributeString( "name", img.title );
|
|
doc.WriteAttributeString( "size", img.Image.Width + ", " + img.Image.Height );
|
|
string img_fname = img.title + ".png";
|
|
img.Image.Save( Path.Combine( image_folder, img_fname ), System.Drawing.Imaging.ImageFormat.Png );
|
|
doc.WriteAttributeString( "path", image_folder_name + "/" + "mouth_" + img_fname );
|
|
}
|
|
doc.WriteEndElement();
|
|
|
|
// トリガー用
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "center", (-img.XOffset) + ", " + (-img.YOffset) );
|
|
doc.WriteAttributeString( "name", "mouth_" + img.title );
|
|
doc.WriteAttributeString( "size", img.Image.Width + ", " + img.Image.Height );
|
|
string img_fname = "mouth_" + img.title + ".png";
|
|
img.Image.Save( Path.Combine( image_folder, img_fname ), System.Drawing.Imaging.ImageFormat.Png );
|
|
doc.WriteAttributeString( "path", image_folder_name + "/" + img_fname );
|
|
doc.WriteAttributeString( "trigger", Translate( img.title ) );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
|
|
// root/mouth_auto_set
|
|
doc.WriteStartElement( "Set" );
|
|
{
|
|
doc.WriteAttributeString( "name", "mouth_auto_set" );
|
|
doc.WriteAttributeString( "size", character.Size.Width + "," + character.Size.Height );
|
|
doc.WriteAttributeString( "count", 1 + "" );
|
|
doc.WriteAttributeString( "trigger", "mouth_auto" );
|
|
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "index", 0 + "" );
|
|
doc.WriteAttributeString( "imageName", "mouth" );
|
|
doc.WriteAttributeString( "offset", "0,0" );
|
|
}
|
|
doc.WriteEndElement();
|
|
sets.Add( "mouth_auto" );
|
|
}
|
|
doc.WriteEndElement();
|
|
|
|
// root/{tag}_manual
|
|
List<string> listed_tag = new List<string>(); // 出力済みのタグのリスト
|
|
bool added = true;
|
|
while ( added ) {
|
|
added = false;
|
|
// 次に出力すべきタグを検索
|
|
string next_tag = "";
|
|
List<string> print = new List<string>();
|
|
foreach ( ImageEntry img in character ) {
|
|
bool found2 = false;
|
|
foreach ( string s in listed_tag ) {
|
|
if ( s == img.tag ) {
|
|
found2 = true;
|
|
break;
|
|
}
|
|
}
|
|
if ( !found2 ) {
|
|
if ( img.tag == "" ) {
|
|
next_tag = group_name_for_empty;
|
|
} else {
|
|
next_tag = img.tag;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( next_tag != "" ) {
|
|
added = true;
|
|
if ( next_tag == group_name_for_empty ) {
|
|
listed_tag.Add( "" );
|
|
} else {
|
|
listed_tag.Add( next_tag );
|
|
}
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( img.tag == next_tag ) {
|
|
print.Add( img.title );
|
|
}
|
|
}
|
|
foreach ( string s in print ) {
|
|
// 本体画像が含まれてたらキャンセル
|
|
if ( s == "base" ) {
|
|
print.Clear();
|
|
break;
|
|
}
|
|
}
|
|
if ( print.Count > 0 ) {
|
|
doc.WriteStartElement( "Set" );
|
|
{
|
|
doc.WriteAttributeString( "name", next_tag + "_manual_set" );
|
|
doc.WriteAttributeString( "trigger", next_tag + "_manual" );
|
|
sets.Add( next_tag + "_manual" );
|
|
doc.WriteAttributeString( "size", character.Size.Width + ", " + character.Size.Height );
|
|
doc.WriteAttributeString( "count", print.Count + "" );
|
|
for ( int i = 0; i < print.Count; i++ ) {
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "index", i + "" );
|
|
if ( IsImageNameForMouth( print[i] ) ) {
|
|
doc.WriteAttributeString( "imageName", "mouth_" + print[i] );
|
|
} else {
|
|
doc.WriteAttributeString( "imageName", print[i] );
|
|
}
|
|
doc.WriteAttributeString( "offset", "0,0" );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// root
|
|
doc.WriteStartElement( "Set" );
|
|
{
|
|
doc.WriteAttributeString( "name", "root" );
|
|
doc.WriteAttributeString( "size", character.Size.Width + ", " + character.Size.Height );
|
|
doc.WriteAttributeString( "count", (1 + sets.Count) + "" );
|
|
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "index", 0 + "" );
|
|
doc.WriteAttributeString( "imageName", "base" );
|
|
doc.WriteAttributeString( "offset", "0,0" );
|
|
}
|
|
doc.WriteEndElement();
|
|
|
|
for ( int i = 0; i < sets.Count; i++ ) {
|
|
doc.WriteStartElement( "Image" );
|
|
{
|
|
doc.WriteAttributeString( "index", (i + 1) + "" );
|
|
doc.WriteAttributeString( "imageName", sets[i] + "_set" );
|
|
doc.WriteAttributeString( "offset", "0,0" );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
doc.WriteEndElement();
|
|
#endregion
|
|
|
|
#region "SingerConfig/Triggers"
|
|
doc.WriteStartElement( "Triggers" );
|
|
{
|
|
foreach ( string s in sets ) {
|
|
doc.WriteStartElement( "Trigger" );
|
|
{
|
|
doc.WriteAttributeString( "group", s + "_control" );
|
|
doc.WriteAttributeString( "name", s );
|
|
if ( s == "mouth_auto" ) {
|
|
doc.WriteAttributeString( "default", "on" );
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( img.title == "base" ) {
|
|
continue;
|
|
}
|
|
doc.WriteStartElement( "Trigger" );
|
|
{
|
|
if ( img.tag == "" ) {
|
|
doc.WriteAttributeString( "group", group_name_for_empty );
|
|
} else {
|
|
doc.WriteAttributeString( "group", img.tag );
|
|
}
|
|
if ( IsImageNameForMouth( img.title ) ) {
|
|
doc.WriteAttributeString( "name", Translate( img.title ) );
|
|
} else {
|
|
doc.WriteAttributeString( "name", img.title );
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
|
|
Dictionary<string, string> dic = new Dictionary<string, string>();
|
|
foreach ( ImageEntry img in character ) {
|
|
if ( img.tag == "" || img.title == "base" ) {
|
|
continue;
|
|
}
|
|
if ( dic.ContainsKey( img.tag ) ) {
|
|
dic[img.tag] = dic[img.tag] + "\n" + img.title;
|
|
} else {
|
|
dic[img.tag] = img.title;
|
|
}
|
|
}
|
|
foreach ( string key in dic.Keys ) {
|
|
string items = dic[key];
|
|
string[] spl = items.Split( "\n".ToCharArray() );
|
|
doc.WriteStartElement( "Selection" );
|
|
{
|
|
foreach ( string s in spl ) {
|
|
doc.WriteStartElement( "Item" );
|
|
{
|
|
doc.WriteAttributeString( "Trigger", s );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
#endregion
|
|
|
|
#region "SingerConfig/Mouths"
|
|
doc.WriteStartElement( "Mouths" );
|
|
{
|
|
doc.WriteStartElement( "Default" );
|
|
{
|
|
doc.WriteAttributeString( "imageName", "nn" );
|
|
}
|
|
doc.WriteEndElement();
|
|
foreach ( string s in dict_text ) {
|
|
string[] spl = s.Split( ",".ToCharArray() );
|
|
doc.WriteStartElement( "Attach" );
|
|
{
|
|
doc.WriteAttributeString( "text", spl[0] );
|
|
doc.WriteAttributeString( "imageName", spl[1] );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
foreach ( string s in dict_symbol ) {
|
|
string[] spl = s.Split( ",".ToCharArray() );
|
|
doc.WriteStartElement( "Attach" );
|
|
{
|
|
doc.WriteAttributeString( "symbol", spl[0] );
|
|
doc.WriteAttributeString( "imageName", spl[1] );
|
|
}
|
|
doc.WriteEndElement();
|
|
}
|
|
}
|
|
doc.WriteEndElement();
|
|
#endregion
|
|
|
|
}
|
|
doc.WriteEndElement();
|
|
doc.Close();
|
|
}
|
|
}
|
|
}
|