2017-09-21 18:33:05 +08:00
|
|
|
|
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;
|
2018-01-12 18:38:49 +08:00
|
|
|
|
using System.IO;
|
2017-09-21 18:33:05 +08:00
|
|
|
|
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; }
|
2018-01-12 18:38:49 +08:00
|
|
|
|
private Texture CurrentTexture = null;
|
|
|
|
|
private float CurrentZoom = 0.0f; //1.0 = 100%, 0.0 = stretch
|
|
|
|
|
|
2017-09-21 18:33:05 +08:00
|
|
|
|
|
|
|
|
|
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;
|
2019-11-09 15:05:41 +08:00
|
|
|
|
List<Texture> texlist = new List<Texture>(texs);
|
|
|
|
|
texlist.Sort((a, b) => { return a.Name?.CompareTo(b.Name) ?? 0; });
|
2017-09-21 18:33:05 +08:00
|
|
|
|
|
2019-11-09 15:05:41 +08:00
|
|
|
|
foreach (var tex in texlist)
|
2017-09-21 18:33:05 +08:00
|
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2018-01-12 18:38:49 +08:00
|
|
|
|
CurrentTexture = tex;
|
|
|
|
|
UpdateSaveAs();
|
|
|
|
|
|
2017-09-21 18:33:05 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-12 18:38:49 +08:00
|
|
|
|
UpdateZoom();
|
2017-09-21 18:33:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateFormTitle()
|
|
|
|
|
{
|
|
|
|
|
Text = fileName + " - Texture Dictionary - CodeWalker by dexyfex";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void UpdateStatus(string text)
|
|
|
|
|
{
|
|
|
|
|
StatusLabel.Text = text;
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-12 18:38:49 +08:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-09-21 18:33:05 +08:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
2018-01-12 18:38:49 +08:00
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
}
|
2017-09-21 18:33:05 +08:00
|
|
|
|
}
|
|
|
|
|
}
|