using CodeWalker.GameFiles; using CodeWalker.Utils; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace CodeWalker.Forms { public partial class YtdForm : Form { private string fileName; private YtdFile Ytd { get; set; } private TextureDictionary TexDict { get; set; } private Texture CurrentTexture = null; private float CurrentZoom = 0.0f; //1.0 = 100%, 0.0 = stretch public YtdForm() { InitializeComponent(); } public void LoadYtd(YtdFile ytd) { Ytd = ytd; fileName = ytd?.Name; if (string.IsNullOrEmpty(fileName)) { fileName = ytd?.RpfFileEntry?.Name; } LoadTexDict(ytd.TextureDict, fileName); } public void LoadTexDict(TextureDictionary texdict, string filename) { TexDict = texdict; fileName = filename; TexturesListView.Items.Clear(); SelTexturePictureBox.Image = null; SelTextureNameTextBox.Text = string.Empty; SelTextureDimensionsLabel.Text = "-"; SelTextureMipLabel.Text = "0"; SelTextureMipTrackBar.Value = 0; SelTextureMipTrackBar.Maximum = 0; if (TexDict == null) { return; } if ((TexDict.Textures == null) || (TexDict.Textures.data_items == null)) return; var texs = TexDict.Textures.data_items; List texlist = new List(texs); texlist.Sort((a, b) => { return a.Name?.CompareTo(b.Name) ?? 0; }); foreach (var tex in texlist) { ListViewItem lvi = TexturesListView.Items.Add(tex.Name); lvi.ToolTipText = tex.Name; lvi.Tag = tex; lvi.SubItems.Add(tex.Width.ToString() + " x " + tex.Height.ToString()); } if (TexturesListView.Items.Count > 0) { TexturesListView.Items[0].Selected = true; } UpdateStatus(GetTexCountStr()); UpdateFormTitle(); } private string GetTexCountStr() { var texs = TexDict?.Textures?.data_items; if (texs == null) return ""; return texs.Length.ToString() + " texture" + ((texs.Length != 1) ? "s" : ""); } private void ShowTextureMip(Texture tex, int mip, bool mipchange) { CurrentTexture = tex; UpdateSaveAs(); if (tex == null) { SelTexturePictureBox.Image = null; SelTextureNameTextBox.Text = string.Empty; SelTextureDimensionsLabel.Text = "-"; SelTextureMipLabel.Text = "0"; SelTextureMipTrackBar.Value = 0; SelTextureMipTrackBar.Maximum = 0; DetailsPropertyGrid.SelectedObject = null; UpdateStatus(GetTexCountStr()); return; } if (mipchange) { if (mip >= tex.Levels) mip = tex.Levels - 1; } else { SelTextureMipTrackBar.Maximum = tex.Levels - 1; } SelTextureNameTextBox.Text = tex.Name; DetailsPropertyGrid.SelectedObject = tex; try { int cmip = Math.Min(Math.Max(mip, 0), tex.Levels - 1); byte[] pixels = DDSIO.GetPixels(tex, cmip); int w = tex.Width >> cmip; int h = tex.Height >> cmip; Bitmap bmp = new Bitmap(w, h, PixelFormat.Format32bppArgb); if (pixels != null) { var BoundsRect = new System.Drawing.Rectangle(0, 0, w, h); BitmapData bmpData = bmp.LockBits(BoundsRect, ImageLockMode.WriteOnly, bmp.PixelFormat); IntPtr ptr = bmpData.Scan0; int bytes = bmpData.Stride * bmp.Height; Marshal.Copy(pixels, 0, ptr, bytes); bmp.UnlockBits(bmpData); } var dimstr = w.ToString() + " x " + h.ToString(); SelTexturePictureBox.Image = bmp; SelTextureDimensionsLabel.Text = dimstr; var str1 = GetTexCountStr(); var str2 = tex.Name + ", mip " + cmip.ToString() + ", " + dimstr; if (!string.IsNullOrEmpty(str1)) { UpdateStatus(str1 + ". " + str2); } else { UpdateStatus(str2); } } catch (Exception ex) { UpdateStatus("Error reading texture mip: " + ex.ToString()); SelTexturePictureBox.Image = null; } UpdateZoom(); } private void UpdateFormTitle() { Text = fileName + " - Texture Dictionary - CodeWalker by dexyfex"; } private void UpdateStatus(string text) { StatusLabel.Text = text; } private void UpdateZoom() { //update the image controls for the current zoom level var img = SelTexturePictureBox.Image; if (CurrentZoom <= 0.0f) { //stretch image to fit the area available. SelTexturePanel.AutoScroll = false; SelTexturePictureBox.SizeMode = PictureBoxSizeMode.Zoom; SelTexturePictureBox.Width = SelTexturePanel.Width - 2; SelTexturePictureBox.Height = SelTexturePanel.Height - 2; SelTexturePictureBox.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; } else { //zoom to the given pixel ratio... var w = (int)(img.Width * CurrentZoom); var h = (int)(img.Height * CurrentZoom); SelTexturePictureBox.Anchor = AnchorStyles.Top | AnchorStyles.Left; SelTexturePictureBox.SizeMode = PictureBoxSizeMode.StretchImage; SelTexturePictureBox.Width = w; SelTexturePictureBox.Height = h; SelTexturePanel.AutoScroll = true; } } private void UpdateSaveAs() { if (CurrentTexture == null) { FileSaveAsMenu.Text = "Save As..."; ToolbarSaveAsMenu.Text = "Save As..."; FileSaveAsMenu.Enabled = false; ToolbarSaveAsMenu.Enabled = false; } else { string fname = CurrentTexture.Name + ".dds"; string sas = "Save " + fname + " As..."; FileSaveAsMenu.Text = sas; ToolbarSaveAsMenu.Text = sas; FileSaveAsMenu.Enabled = true; ToolbarSaveAsMenu.Enabled = true; } } private void SaveAs() { if (CurrentTexture == null) return; string fname = CurrentTexture.Name + ".dds"; SaveFileDialog.FileName = fname; if (SaveFileDialog.ShowDialog() != DialogResult.OK) return; string fpath = SaveFileDialog.FileName; byte[] dds = DDSIO.GetDDSFile(CurrentTexture); File.WriteAllBytes(fpath, dds); } private void SaveAll() { if (TexDict?.Textures?.data_items == null) return; if (FolderBrowserDialog.ShowDialog() != DialogResult.OK) return; var folder = FolderBrowserDialog.SelectedPath; foreach (var tex in TexDict.Textures.data_items) { byte[] dds = DDSIO.GetDDSFile(tex); string bpath = folder + "\\" + tex.Name; string fpath = bpath + ".dds"; int c = 1; while (File.Exists(fpath)) { fpath = bpath + "_Copy" + c.ToString() + ".dds"; c++; } File.WriteAllBytes(fpath, dds); } } private void TexturesListView_SelectedIndexChanged(object sender, EventArgs e) { Texture tex = null; if (TexturesListView.SelectedItems.Count == 1) { tex = TexturesListView.SelectedItems[0].Tag as Texture; } ShowTextureMip(tex, 0, false); } private void SelTextureMipTrackBar_Scroll(object sender, EventArgs e) { Texture tex = null; if (TexturesListView.SelectedItems.Count == 1) { tex = TexturesListView.SelectedItems[0].Tag as Texture; } SelTextureMipLabel.Text = SelTextureMipTrackBar.Value.ToString(); ShowTextureMip(tex, SelTextureMipTrackBar.Value, true); } private void SelTextureZoomCombo_TextChanged(object sender, EventArgs e) { string s = SelTextureZoomCombo.Text; if (s.EndsWith("%")) s = s.Substring(0, s.Length - 1); float f; if (!float.TryParse(s, out f)) { CurrentZoom = 0.0f; } else { CurrentZoom = Math.Min(Math.Max(f, 0.0f), 5000.0f) * 0.01f; } UpdateZoom(); } private void FileSaveAllMenu_Click(object sender, EventArgs e) { SaveAll(); } private void FileSaveAsMenu_Click(object sender, EventArgs e) { SaveAs(); } private void SaveButton_ButtonClick(object sender, EventArgs e) { SaveAs(); } private void ToolbarSaveAsMenu_Click(object sender, EventArgs e) { SaveAs(); } private void ToolbarSaveAllMenu_Click(object sender, EventArgs e) { SaveAll(); } } }