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();
}
}
}