using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; using Microsoft.Win32; namespace Tso2MqoGui { public partial class Form1 : Form { public string OutPath { get { return tbPath.Text; } set { tbPath.Text= value; } } public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { RegistryKey reg = Application.UserAppDataRegistry.CreateSubKey("Config"); OutPath = (string)reg.GetValue("OutPath", Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments)); tabControl1.SelectedIndex = (int)reg.GetValue("TabPage", 0); tbMqoFile.Text = (string)reg.GetValue("MqoIn", ""); tbTsoFileRef.Text = (string)reg.GetValue("Tso", ""); tbTsoFile.Text = (string)reg.GetValue("TsoEx", ""); tbMergeTso.Text = (string)reg.GetValue("MergeTso", ""); rbRefBone.Checked = (int)reg.GetValue("RefBone", 1) == 1; rbOneBone.Checked = (int)reg.GetValue("OneBone", 0) == 1; rbBoneNone.Checked = (int)reg.GetValue("BoneNone", 1) == 1; rbBoneRokDeBone.Checked = (int)reg.GetValue("BoneRokDeBone", 0) == 1; cbMakeSub.Checked = (int)reg.GetValue("MakeSub", 1) == 1; cbCopyTSO.Checked = (int)reg.GetValue("CopyTSO", 1) == 1; cbShowMaterials.Checked = (int)reg.GetValue("ShowMaterials", 0) == 1; reg = Application.UserAppDataRegistry.CreateSubKey("Form1"); Bounds = new Rectangle( (int)reg.GetValue("Left", 0), (int)reg.GetValue("Top", 0), (int)reg.GetValue("Width", 640), (int)reg.GetValue("Height", 320)); EnableControlStuff(); Config config = Config.Instance; } private void Form1_FormClosed(object sender, FormClosedEventArgs e) { RegistryKey reg = Application.UserAppDataRegistry.CreateSubKey("Config"); reg.SetValue("OutPath", OutPath); reg.SetValue("TabPage", tabControl1.SelectedIndex); reg.SetValue("MqoIn", tbMqoFile.Text); reg.SetValue("Tso", tbTsoFileRef.Text); reg.SetValue("TsoEx", tbTsoFile.Text); reg.SetValue("MergeTso", tbMergeTso.Text); reg.SetValue("RefBone", rbRefBone.Checked ? 1 : 0); reg.SetValue("OneBone", rbOneBone.Checked ? 1 : 0); reg.SetValue("BoneNone", rbBoneNone.Checked ? 1 : 0); reg.SetValue("BoneRokDeBone", rbBoneRokDeBone.Checked ? 1 : 0); reg.SetValue("MakeSub", cbMakeSub.Checked ? 1 : 0); reg.SetValue("CopyTSO", cbCopyTSO.Checked ? 1 : 0); reg.SetValue("ShowMaterials", cbShowMaterials.Checked ? 1 : 0); reg= Application.UserAppDataRegistry.CreateSubKey("Form1"); if((this.WindowState & FormWindowState.Minimized) == FormWindowState.Minimized) { reg.SetValue("Top", RestoreBounds.Top); reg.SetValue("Left", RestoreBounds.Left); reg.SetValue("Width", RestoreBounds.Width); reg.SetValue("Height", RestoreBounds.Height); } else { reg.SetValue("Top", Top); reg.SetValue("Left", Left); reg.SetValue("Width", Width); reg.SetValue("Height", Height); } Config.Save(); } private void Form1_DragDrop(object sender, DragEventArgs e) { try { if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return; string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); if(files.Length == 0) return; switch(tabControl1.SelectedIndex) { case 0: foreach(string i in files) { if(Path.GetExtension(i).ToUpper() == ".TSO") OpenTSOFile(i); } break; case 1: switch (Path.GetExtension(files[0]).ToUpper()) { case ".TSO": tbTsoFileRef.Text = files[0]; break; case ".MQO": tbMqoFile.Text = files[0]; break; } break; case 2: AddMergeTso(files); break; } } catch(Exception ex) { Util.ProcessError(ex); } } private void Form1_DragEnter(object sender, DragEventArgs e) { if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return; e.Effect = DragDropEffects.Copy; } private void tbMergeTso_DragDrop(object sender, DragEventArgs e) { if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return; string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); switch(Path.GetExtension(files[0]).ToUpper()) { case ".TSO": tbMergeTso.Text= files[0]; break; } } private void tbMergeTso_DragEnter(object sender, DragEventArgs e) { if(!e.Data.GetDataPresent(DataFormats.FileDrop)) return; e.Effect = DragDropEffects.Copy; } private void OpenTSOFile(string file) { string dir = OutPath; if (cbMakeSub.Checked) { dir = Path.Combine(dir, Path.GetFileNameWithoutExtension(file)); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); } string mqo_path = Path.Combine(dir, Path.ChangeExtension(Path.GetFileName(file), ".mqo")); string importinfo_path = Path.Combine(dir, Path.ChangeExtension(Path.GetFileName(file), ".xml")); try { label2.BackColor = Color.Tomato; label2.ForeColor = Color.White; label2.Text = "Processing"; label2.Invalidate(); label2.Update(); // モデル、テクスチャの作成 using (MqoWriter mqo = new MqoWriter(mqo_path)) { TSOFile tso = new TSOFile(file); tso.ReadAll(); if (rbBoneRokDeBone.Checked) mqo.BoneMode = MqoBoneMode.RokDeBone; mqo.Write(tso); mqo.Close(); ImportInfo ii = new ImportInfo(); // テクスチャ情報 foreach (TSOTex i in tso.textures) ii.textures.Add(new ImportTextureInfo(i)); // エフェクトの作成 foreach (TSOEffect i in tso.effects) { ii.effects.Add(new ImportEffectInfo(i)); File.WriteAllText(Path.Combine(dir, i.Name), i.code, Encoding.Default); } // マテリアルの作成 foreach (TSOMaterial i in tso.materials) { ii.materials.Add(new ImportMaterialInfo(i)); File.WriteAllText(Path.Combine(dir, i.Name), i.code, Encoding.Default); } ImportInfo.Save(importinfo_path, ii); } if (cbCopyTSO.Checked) { string tso_path = Path.Combine(dir, Path.GetFileName(file)); if (file != tso_path) File.Copy(file, tso_path, true); } } finally { label2.BackColor = SystemColors.Control; label2.BackColor = label2.Parent.BackColor; label2.ForeColor = SystemColors.ControlText; label2.Text = "Drop TSO File Here!"; } } private void OpenMQOFile(string file) { TSOGeneratorConfig config = new TSOGeneratorConfig(); config.ShowMaterials = cbShowMaterials.Checked; if (rbRefBone.Checked) { TSOGeneratorRefBone gen = new TSOGeneratorRefBone(config); gen.Generate(file, tbTsoFileRef.Text, tbTsoFile.Text); } else if (rbOneBone.Checked) { TSOGeneratorOneBone gen = new TSOGeneratorOneBone(config); foreach (ListViewItem i in lvObjects.Items) { if (i.SubItems[1].Text == "") { MessageBox.Show("すべてのオブジェクトにボーンを設定してください"); return; } gen.ObjectBoneNames.Add(i.SubItems[0].Text, i.SubItems[1].Text); } gen.Generate(file, tbTsoFileRef.Text, tbTsoFile.Text); } else { } } #region tso->mqo UI private void button1_Click(object sender, EventArgs e) { FolderBrowserDialog dlg = new FolderBrowserDialog(); dlg.SelectedPath = OutPath; if(dlg.ShowDialog() == DialogResult.OK) OutPath = dlg.SelectedPath; } #endregion #region mqo->tso UI private void radioButton1_CheckedChanged(object sender, EventArgs e) { EnableControlStuff(); } private void radioButton2_CheckedChanged(object sender, EventArgs e) { EnableControlStuff(); } private void EnableControlStuff() { gbBone.Enabled = rbOneBone.Checked; } private void BuildBoneTree(TreeNodeCollection nodes, TSONode node) { TreeNode tn = nodes.Add(node.ShortName); tn.Tag = node; if(node.children != null) foreach(TSONode i in node.children) BuildBoneTree(tn.Nodes, i); } private void SaveAssign() { foreach(ListViewItem i in lvObjects.Items) { string obj = i.SubItems[0].Text; string bone= i.SubItems[1].Text; if(Config.Instance.object_bone_map.ContainsKey(obj)) Config.Instance.object_bone_map[obj] = bone; else Config.Instance.object_bone_map.Add(obj, bone); } } private void btnMqoFile_Click(object sender, EventArgs e) { try { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "Metasequoia File (*.mqo)|*.mqo"; dlg.FileName = tbMqoFile.Text; if (dlg.ShowDialog() == DialogResult.OK) tbMqoFile.Text = dlg.FileName; } catch (Exception ex) { Util.ProcessError(ex); } } private void btnTsoFileRef_Click(object sender, EventArgs e) { try { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "TSO File (*.tso)|*.tso"; dlg.FileName = tbTsoFileRef.Text; if (dlg.ShowDialog() == DialogResult.OK) tbTsoFileRef.Text = dlg.FileName; } catch (Exception ex) { Util.ProcessError(ex); } } private void btnTsoFile_Click(object sender, EventArgs e) { try { SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "TSO File (*.tso)|*.tso"; dlg.FileName = tbTsoFile.Text; if (dlg.ShowDialog() == DialogResult.OK) tbTsoFile.Text = dlg.FileName; } catch (Exception ex) { Util.ProcessError(ex); } } private void btnRefresh_Click(object sender, EventArgs e) { try { // 一旦現状を保存 SaveAssign(); // オブジェクト MqoFile mqo = new MqoFile(); mqo.Load(tbMqoFile.Text); lvObjects.Items.Clear(); foreach (MqoObject i in mqo.Objects) { ListViewItem item = lvObjects.Items.Add(i.name); item.Tag = i; string bone; if (Config.Instance.object_bone_map.TryGetValue(i.name, out bone)) item.SubItems.Add(bone); else item.SubItems.Add(""); } // ボーン構造 TSOFile tso = new TSOFile(tbTsoFileRef.Text); tso.ReadAll(); tvBones.Visible = false; tvBones.Nodes.Clear(); BuildBoneTree(tvBones.Nodes, tso.nodes[0]); tvBones.ExpandAll(); tvBones.Nodes[0].EnsureVisible(); } catch (Exception ex) { Util.ProcessError(ex); } finally { tvBones.Visible = true; } } private void btnSelectAll_Click(object sender, EventArgs e) { foreach (ListViewItem i in lvObjects.Items) i.Selected = true; } private void btnDeselectAll_Click(object sender, EventArgs e) { foreach (ListViewItem i in lvObjects.Items) i.Selected = false; } private void btnAssign_Click(object sender, EventArgs e) { try { TreeNode n = tvBones.SelectedNode; if (n == null) { MessageBox.Show("割り当てるボーンを選択してください"); return; } foreach (ListViewItem i in lvObjects.SelectedItems) i.SubItems[1].Text = n.Text; SaveAssign(); } catch (Exception ex) { Util.ProcessError(ex); } } private void btnGenerate_Click(object sender, EventArgs e) { Color c = tabPage2.BackColor; try { tabPage2.BackColor = Color.Tomato; tabPage2.Update(); string file = tbMqoFile.Text; OpenMQOFile(file); } catch (Exception ex) { Util.ProcessError(ex); } finally { tabPage2.BackColor = c; } } #endregion #region Merge UI private void AddMergeTso(string[] files) { foreach(string i in files) { if(Path.GetExtension(files[0]).ToUpper() != ".TSO") continue; if(tvMerge.Nodes.Find(i, false).Length == 0) { TreeNode node= tvMerge.Nodes.Add(i); node.Name = i; node.Checked = true; TSOFile tso = new TSOFile(i); tso.ReadAll(); foreach(TSOMesh j in tso.meshes) { TreeNode mesh= node.Nodes.Add(j.Name); mesh.Name = j.Name; mesh.Checked = true; } } } } private void btnMerge_Click(object sender, EventArgs e) { Color c = tabPage2.BackColor; try { tabPage2.BackColor = Color.Tomato; List meshes = new List(); Dictionary> materialmap = new Dictionary>(); Dictionary textures = new Dictionary(); TSOFile last = null; foreach (TreeNode i in tvMerge.Nodes) { TSOFile tso = new TSOFile(i.Text); last = tso; ulong mtls = 0; ulong mask = 1; tso.ReadAll(); foreach (TSOMesh j in tso.meshes) { TreeNode[] found = i.Nodes.Find(j.Name, false); if (found.Length == 0 || !found[0].Checked) continue; foreach (TSOSubMesh k in j.sub) mtls |= 1ul << k.spec; meshes.Add(j); } foreach (TSOMaterial j in tso.materials) { if ((mask & mtls) != 0) { if (!materialmap.ContainsKey(j.Name)) { Pair value = new Pair(j, materialmap.Count); materialmap.Add(j.Name, value); if (!textures.ContainsKey(j.ColorTex)) { TSOTex tex = tso.texturemap[j.ColorTex]; textures.Add(tex.Name, tex); } if (!textures.ContainsKey(j.ShadeTex)) { TSOTex tex = tso.texturemap[j.ShadeTex]; textures.Add(tex.Name, tex); } } } mask <<= 1; } } using (FileStream fs = File.OpenWrite(tbMergeTso.Text)) { fs.SetLength(0); List texlist = new List(textures.Values); TSOMaterial[] mtllist = new TSOMaterial[materialmap.Count]; foreach (var i in materialmap.Values) mtllist[i.Second] = i.First; foreach (TSOMesh i in meshes) { foreach (TSOSubMesh j in i.sub) { TSOMaterial mtl = i.file.materials[j.spec]; j.spec = materialmap[mtl.Name].Second; } } foreach (TSOTex i in texlist) TSOFile.ExchangeChannel(i.data, i.depth); BinaryWriter bw = new BinaryWriter(fs); TSOWriter.WriteHeader(bw); TSOWriter.Write(bw, last.nodes); TSOWriter.Write(bw, texlist.ToArray()); TSOWriter.Write(bw, last.effects); TSOWriter.Write(bw, mtllist); TSOWriter.Write(bw, meshes.ToArray()); } } catch (Exception ex) { Util.ProcessError(ex); } finally { tabPage2.BackColor = c; } } private void btnMergeAdd_Click(object sender, EventArgs e) { try { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "TSO File(*.tso)|*.tso"; dlg.Multiselect = true; if(dlg.ShowDialog() == DialogResult.OK) AddMergeTso(dlg.FileNames); } catch(Exception ex) { Util.ProcessError(ex); } } private void btnMergeDel_Click(object sender, EventArgs e) { if (tvMerge.SelectedNode != null && tvMerge.SelectedNode.Level == 0) tvMerge.SelectedNode.Remove(); } private void btnMergeReset_Click(object sender, EventArgs e) { tvMerge.Nodes.Clear(); } private void btnRefMergeTso_Click(object sender, EventArgs e) { try { SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "TSO File (*.tso)|*.tso"; dlg.FileName = tbMergeTso.Text; if (dlg.ShowDialog() == DialogResult.OK) tbMergeTso.Text = dlg.FileName; } catch (Exception ex) { Util.ProcessError(ex); } } public static bool bTvMerge_AfterCheck = false; private void tvMerge_AfterCheck(object sender, TreeViewEventArgs e) { if(bTvMerge_AfterCheck) return; bTvMerge_AfterCheck = true; try { if(e.Node.Level == 0) { foreach(TreeNode i in e.Node.Nodes) i.Checked = e.Node.Checked; } else { bool check = false; //bool uncheck = false; foreach(TreeNode i in e.Node.Parent.Nodes) if(i.Checked) check = true; //else uncheck = true; e.Node.Parent.Checked = check; } } finally { bTvMerge_AfterCheck = false; } } #endregion } public class Util { public static void ProcessError(Exception e) { MessageBox.Show(e.ToString()); } } }