diff --git a/Controls/SearchBox.cs b/Controls/SearchBox.cs new file mode 100644 index 0000000..652ea76 --- /dev/null +++ b/Controls/SearchBox.cs @@ -0,0 +1,221 @@ +using System; +using System.ComponentModel; +using System.Windows.Forms; + +namespace Controls +{ + public partial class SearchBox : UserControl + { + [Browsable(true)] + public DataGridView DataGridView { get; set; } + int CurrentRowIndex = -1; + int CurrentColumnIndex = -1; + + public SearchBox() + { + InitializeComponent(); + Hide(); + } + public SearchBox(DataGridView dataGrid) + { + DataGridView = dataGrid; + InitializeComponent(); + Hide(); + } + + private void SearchHide_Click(object sender, System.EventArgs e) + { + Hide(); + } + + private bool IsMatch(string value) + { + string searchText = InputSearch.Text; + + if (string.IsNullOrWhiteSpace(searchText)) + return false; + + return value.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) > -1; + } + + private void FindNext_Click(object sender, EventArgs e) + { + bool found = false; + + for (int rowIndex = CurrentRowIndex; rowIndex < DataGridView.Rows.Count; rowIndex++) + { + for (int colIndex = CurrentColumnIndex + 1; colIndex < DataGridView.Columns.Count; colIndex++) + { + if (rowIndex >= 0 && rowIndex < DataGridView.Rows.Count && colIndex >= 0 && colIndex < DataGridView.Columns.Count) + { + DataGridViewCell cell = DataGridView.Rows[rowIndex].Cells[colIndex]; + if (cell.Value != null && IsMatch(cell.Value.ToString())) + { + SelectCell(rowIndex, colIndex); + found = true; + break; + } + } + } + + if (found) + break; + + + CurrentColumnIndex = -1; + } + + if (!found) + { + + for (int rowIndex = 0; rowIndex < DataGridView.Rows.Count; rowIndex++) + { + for (int colIndex = 0; colIndex < DataGridView.Columns.Count; colIndex++) + { + if (rowIndex >= 0 && rowIndex < DataGridView.Rows.Count && colIndex >= 0 && colIndex < DataGridView.Columns.Count) + { + DataGridViewCell cell = DataGridView.Rows[rowIndex].Cells[colIndex]; + if (cell.Value != null && IsMatch(cell.Value.ToString())) + { + SelectCell(rowIndex, colIndex); + found = true; + break; + } + } + } + + if (found) + break; + } + } + if (!found) + { + Failedmessage(); + } + } + + + private void FindPrevious_Click(object sender, EventArgs e) + { + bool found = false; + + for (int rowIndex = CurrentRowIndex; rowIndex >= 0; rowIndex--) + { + for (int colIndex = CurrentColumnIndex - 1; colIndex >= 0; colIndex--) + { + if (rowIndex >= 0 && rowIndex < DataGridView.Rows.Count && colIndex >= 0 && colIndex < DataGridView.Columns.Count) + { + DataGridViewCell cell = DataGridView.Rows[rowIndex].Cells[colIndex]; + if (cell.Value != null && IsMatch(cell.Value.ToString())) + { + SelectCell(rowIndex, colIndex); + found = true; + break; + } + } + } + + if (found) + break; + + + CurrentColumnIndex = DataGridView.Columns.Count; + } + + if (!found) + { + for (int rowIndex = DataGridView.Rows.Count - 1; rowIndex >= 0; rowIndex--) + { + for (int colIndex = DataGridView.Columns.Count - 1; colIndex >= 0; colIndex--) + { + if (rowIndex >= 0 && rowIndex < DataGridView.Rows.Count && colIndex >= 0 && colIndex < DataGridView.Columns.Count) + { + DataGridViewCell cell = DataGridView.Rows[rowIndex].Cells[colIndex]; + if (cell.Value != null && IsMatch(cell.Value.ToString())) + { + SelectCell(rowIndex, colIndex); + found = true; + break; + } + } + } + + if (found) + break; + } + } + + if (!found) + { + Failedmessage(); + } + } + + + private void Failedmessage() + { + MessageBox.Show( + text: $"The searched value '{InputSearch.Text}' not found.", + caption: "Search Result", + buttons: MessageBoxButtons.OK, + icon: MessageBoxIcon.Warning + ); + } + + private void SelectCell(int rowIndex, int colIndex) + { + DataGridView.ClearSelection(); + DataGridView.FirstDisplayedScrollingRowIndex = rowIndex; + DataGridView.Rows[rowIndex].Cells[colIndex].Selected = true; + + CurrentRowIndex = rowIndex; + CurrentColumnIndex = colIndex; + } + + private void InputSearch_KeyDown(object sender, KeyEventArgs e) + { + if (!InputSearch.Focused) + { + InputSearch.Focus(); + } + + if (e.KeyCode == Keys.Enter) + { + FindNext_Click(sender, e); + } + } + + public new void Show() + { + if (DataGridView.CurrentCell!=null) + { + InputSearch.Text = DataGridView.CurrentCell.Value.ToString(); + } + InputSearch.Focus(); + base.Show(); + } + + public int CountTotalMatches() + { + int totalMatches = 0; + + for (int rowIndex = 0; rowIndex < DataGridView.Rows.Count; rowIndex++) + { + for (int colIndex = 0; colIndex < DataGridView.Columns.Count; colIndex++) + { + if (rowIndex >= 0 && rowIndex < DataGridView.Rows.Count && colIndex >= 0 && colIndex < DataGridView.Columns.Count) + { + DataGridViewCell cell = DataGridView.Rows[rowIndex].Cells[colIndex]; + if (cell.Value != null && IsMatch(cell.Value.ToString())) + { + totalMatches++; + } + } + } + } + + return totalMatches; + } + + } +} diff --git a/Controls/SearchBox.designer.cs b/Controls/SearchBox.designer.cs new file mode 100644 index 0000000..2cb1146 --- /dev/null +++ b/Controls/SearchBox.designer.cs @@ -0,0 +1,126 @@ +using System; +using System.Windows.Forms; + +namespace Controls +{ + partial class SearchBox + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.searchcount = new System.Windows.Forms.Label(); + this.SearchHide = new System.Windows.Forms.Label(); + this.FindPrevious = new System.Windows.Forms.Button(); + this.FindNext = new System.Windows.Forms.Button(); + this.InputSearch = new TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // searchcount + // + this.searchcount.Location = new System.Drawing.Point(423, 7); + this.searchcount.Name = "searchcount"; + this.searchcount.Size = new System.Drawing.Size(211, 18); + this.searchcount.TabIndex = 6; + // + // SearchHide + // + this.SearchHide.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.SearchHide.AutoSize = true; + this.SearchHide.Cursor = System.Windows.Forms.Cursors.Hand; + this.SearchHide.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F, System.Drawing.FontStyle.Bold); + this.SearchHide.Location = new System.Drawing.Point(665, 7); + this.SearchHide.Name = "SearchHide"; + this.SearchHide.Size = new System.Drawing.Size(18, 17); + this.SearchHide.TabIndex = 5; + this.SearchHide.Text = "X"; + this.SearchHide.Click += new System.EventHandler(this.SearchHide_Click); + // + // FindPrevious + // + this.FindPrevious.Location = new System.Drawing.Point(331, 4); + this.FindPrevious.Name = "FindPrevious"; + this.FindPrevious.Size = new System.Drawing.Size(86, 23); + this.FindPrevious.TabIndex = 4; + this.FindPrevious.Text = "Find Previous"; + this.FindPrevious.UseVisualStyleBackColor = true; + this.FindPrevious.Click += new System.EventHandler(this.FindPrevious_Click); + // + // FindNext + // + this.FindNext.Location = new System.Drawing.Point(250, 4); + this.FindNext.Name = "FindNext"; + this.FindNext.Size = new System.Drawing.Size(75, 23); + this.FindNext.TabIndex = 3; + this.FindNext.Text = "Find Next"; + this.FindNext.UseVisualStyleBackColor = true; + this.FindNext.Click += new System.EventHandler(this.FindNext_Click); + // + // InputSearch + // + this.InputSearch.Location = new System.Drawing.Point(79, 5); + this.InputSearch.Name = "InputSearch"; + this.InputSearch.Size = new System.Drawing.Size(162, 20); + this.InputSearch.TabIndex = 0; + this.InputSearch.KeyDown += new System.Windows.Forms.KeyEventHandler(this.InputSearch_KeyDown); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(56, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Find what:"; + // + // SearchBox + // + this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.Controls.Add(this.searchcount); + this.Controls.Add(this.SearchHide); + this.Controls.Add(this.FindPrevious); + this.Controls.Add(this.FindNext); + this.Controls.Add(this.label1); + this.Controls.Add(this.InputSearch); + this.Location = new System.Drawing.Point(155, 23); + this.Name = "SearchBox"; + this.Size = new System.Drawing.Size(689, 30); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label searchcount; + private System.Windows.Forms.Label SearchHide; + private System.Windows.Forms.Button FindPrevious; + private System.Windows.Forms.Button FindNext; + + private System.Windows.Forms.Label label1; + public TextBox InputSearch; + } +} diff --git a/Controls/SearchBox.resx b/Controls/SearchBox.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Controls/SearchBox.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Core/StringTable/StringTable.cs b/Core/StringTable/StringTable.cs index 840dda1..ffdbb67 100644 --- a/Core/StringTable/StringTable.cs +++ b/Core/StringTable/StringTable.cs @@ -7,10 +7,45 @@ namespace alan_wake_2_rmdtoc_Tool.Core.StringTable public class SrtingTableEntry { - public string Name; - public string Value; + private string _Name; + private string _Value; + public string Name + { + get + { + return ReplaceBreaklines(_Name); + } + set + { + _Name = ReplaceBreaklines(value, true); + } + } + public string Value + { + get { return ReplaceBreaklines(_Value); } + set { _Value = ReplaceBreaklines(value, true); } + } + + private static string ReplaceBreaklines(string StringValue, bool Back = false) + { + if (!Back) + { + StringValue = StringValue.Replace("\r\n", ""); + StringValue = StringValue.Replace("\r", ""); + StringValue = StringValue.Replace("\n", ""); + } + else + { + StringValue = StringValue.Replace("", "\r\n"); + StringValue = StringValue.Replace("", "\r"); + StringValue = StringValue.Replace("", "\n"); + } + + return StringValue; + } } + public class StringTable : List, IStringTable { public IStream Stream; @@ -27,7 +62,7 @@ void ReadStringTable() { var Entry = new SrtingTableEntry(); - Entry.Name = Stream.GetStringValue(Stream.GetIntValue()); + Entry.Name = Stream.GetStringValue(Stream.GetIntValue(), Encoding.UTF8); Entry.Value = Stream.GetStringValue(Stream.GetIntValue() * 2, Encoding.Unicode); Add(Entry); } @@ -42,7 +77,7 @@ public void BuildStringTable() for (int i = 0; i < Count; i++) { var Entry = this[i]; - var Bytes = Encoding.ASCII.GetBytes(Entry.Name); + var Bytes = Encoding.UTF8.GetBytes(Entry.Name); Stream.SetIntValue(Bytes.Length); Stream.SetBytes(Bytes); Bytes = Encoding.Unicode.GetBytes(Entry.Value); diff --git a/Core/rmdtoc.cs b/Core/rmdtoc.cs index f03aa9b..fa66c27 100644 --- a/Core/rmdtoc.cs +++ b/Core/rmdtoc.cs @@ -23,8 +23,8 @@ public class rmdtocHeader public int CompressionInfoTableOffset; public int CompressionInfoTableSize; - public int Unko2;//=0 - public int Unko3;//=1 + public int RMDBLOB_Path_Offset; + public int RMDBLOB_Path_Count; public int Table_1_Offset;//Table size is Table_1_Count* 0x1C public int Table_1_Count; @@ -48,16 +48,78 @@ public class rmdtocHeader public int Table_5_Size; } - [StructLayout(LayoutKind.Sequential, Pack = 1)] + + public class RMDBLOBPath + { + public const int Size = 0x10; + public int NameOffset; + public int NameLength; + public ulong Hash; + public string Path; + + public void Read(IStream stream) + { + NameOffset = stream.Get(); + NameLength = stream.Get(); + Hash = stream.Get(); + } + + public void Write(IStream stream) + { + stream.SetIntValue(NameOffset); + stream.SetIntValue(NameLength); + stream.SetUInt64Value(Hash); + } + } + public class CompressInfo { - public byte unko; + public const int Size = 0x10; + public byte isCompressed; public byte FileIndex; public byte unko2; - public int BufferOffset; + public uint _bufferoffset; public byte unko3; public int BufferUSize; public int BufferSize; + + public long BufferOffset + { + get + { + long value = _bufferoffset; + return value + (unko3 * 0x100000000); + } + set + { + long newUnko3 = value / 0x100000000; + unko3 = (byte)newUnko3; + _bufferoffset = (uint)(value - (newUnko3 * 0x100000000)); + } + } + + public void Read(IStream stream) + { + isCompressed = stream.Get(); + FileIndex = stream.Get(); + unko2 = stream.Get(); + _bufferoffset = stream.Get(); + unko3 = stream.Get(); + BufferUSize = stream.Get(); + BufferSize = stream.Get(); + } + + public void Write(IStream stream) + { + stream.SetByteValue(isCompressed); + stream.SetByteValue(FileIndex); + stream.SetByteValue(unko2); + stream.SetUIntValue(_bufferoffset); + stream.SetByteValue(unko3); + stream.SetIntValue(BufferUSize); + stream.SetIntValue(BufferSize); + } + } @@ -65,9 +127,9 @@ public class FolderInfo { const int Size = 0x1c; + public int TreeLevel; public int FolderIndex; - public int unko; - public int unko2; + public int FolderCount; public int FilesIndex; public int FilesCount; public int NameOffset; @@ -80,9 +142,9 @@ public class FolderInfo public void Read(IStream stream) { + TreeLevel = stream.Get(); FolderIndex = stream.Get(); - unko = stream.Get(); - unko2 = stream.Get(); + FolderCount = stream.Get(); FilesIndex = stream.Get(); FilesCount = stream.Get(); NameOffset = stream.Get(); @@ -91,9 +153,9 @@ public void Read(IStream stream) public void Write(IStream stream) { + stream.SetIntValue(TreeLevel); stream.SetIntValue(FolderIndex); - stream.SetIntValue(unko); - stream.SetIntValue(unko2); + stream.SetIntValue(FolderCount); stream.SetIntValue(FilesIndex); stream.SetIntValue(FilesCount); stream.SetIntValue(NameOffset); @@ -117,17 +179,13 @@ public class FileInfo public rmdtoc Rmdtoc; - public CompressInfo[] CompressInfos; + public List CompressInfos; public string Name; - public bool IsEdited = false; - public byte[] NewFileBytes; - - public void Read(IStream stream) { CompressionInfoTableOffset = stream.Get(); @@ -153,12 +211,15 @@ public void Write(IStream stream) public string GetOffset() { - int offset = 0; + + long offset = 0; foreach (var item in CompressInfos) { offset += item.BufferOffset; break; } + + Console.WriteLine(offset); return "0x" + offset.ToString("X"); } @@ -181,18 +242,16 @@ public byte[] GetFile() foreach (var info in CompressInfos) { - string path = Path.ChangeExtension(Rmdtoc.rmdtocStream.Name, null) + "-" + info.FileIndex.ToString("D3") + ".rmdblob"; - Console.WriteLine(path); - var stream = new FStream(path, FileMode.Open, FileAccess.Read); - - if (info.BufferSize == 0) + var stream = new FStream(GetRMDBLOBPath(info), FileMode.Open, FileAccess.Read); + stream.Position = info.BufferOffset; + if (info.BufferSize == 0 || info.isCompressed == 0) { - DecompressBuffer.SetBytes(stream.GetBytes(info.BufferUSize, false, info.BufferOffset)); + DecompressBuffer.SetBytes(stream.GetBytes(info.BufferUSize)); } else { - DecompressBuffer.SetBytes(LZ4Codec.Decode(stream.GetBytes(info.BufferSize, false, info.BufferOffset), 0, info.BufferSize, info.BufferUSize)); + DecompressBuffer.SetBytes(LZ4Codec.Decode(stream.GetBytes(info.BufferSize), 0, info.BufferSize, info.BufferUSize)); } stream.Close(); } @@ -201,26 +260,75 @@ public byte[] GetFile() return DecompressBuffer.ToArray(); } - public string GetId() + + public string GetRMDBLOBPath(CompressInfo info) + { + return Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Rmdtoc.rmdtocStream.Name), Rmdtoc.RMDBLOBPaths[info.FileIndex].Path)); + } + + public string GetRMDBLOBPath() { - if (CompressInfos.Length == 0) + if(CompressInfos.Count==0) { return ""; } + return Path.GetFullPath( Path.Combine(Path.GetDirectoryName(Rmdtoc.rmdtocStream.Name), Rmdtoc.RMDBLOBPaths[CompressInfos[0].FileIndex].Path)); + } + public byte[] GetRow() + { - string path = Path.ChangeExtension(Rmdtoc.rmdtocStream.Name, null) + "-" + CompressInfos[0].FileIndex.ToString("D3") + ".rmdblob"; - Console.WriteLine(path); - var stream = new FStream(path, FileMode.Open, FileAccess.Read); + var DecompressBuffer = new MStream(); + foreach (var info in CompressInfos) + { + + var stream = new FStream(GetRMDBLOBPath(info), FileMode.Open, FileAccess.Read); + + stream.Position = info.BufferOffset; + DecompressBuffer.SetStringValue("Offset: " + stream.Position); + DecompressBuffer.SetStringValue("Size: " + info.BufferSize); + DecompressBuffer.SetStringValue("USize: " + info.BufferUSize); + DecompressBuffer.SetStringValue("IsCompressed: " + info.isCompressed); + DecompressBuffer.SetStringValue("Start"); + + if (info.BufferSize == 0 || info.isCompressed == 0) + { + DecompressBuffer.SetBytes(stream.GetBytes(info.BufferUSize)); + } + else + { + DecompressBuffer.SetBytes(stream.GetBytes(info.BufferSize)); + } + DecompressBuffer.SetStringValue("End of File"); + + stream.Close(); + } + + + return DecompressBuffer.ToArray(); + + + + } + public string GetId() + { + if (CompressInfos.Count == 0) + { + return ""; + } + + var stream = new FStream(GetRMDBLOBPath(CompressInfos[0]), FileMode.Open, FileAccess.Read); string id; if (CompressInfos[0].BufferSize == 0) { - id = stream.GetStringValue(4, false, CompressInfos[0].BufferOffset); + stream.Position = CompressInfos[0].BufferOffset; + id = stream.GetStringValue(4); } else { - id = stream.GetStringValue(4, false, CompressInfos[0].BufferOffset + 1); + stream.Position = CompressInfos[0].BufferOffset + 1; + id = stream.GetStringValue(4); } @@ -233,22 +341,34 @@ public string GetId() public void SetFile() { var info = CompressInfos[0]; - string path = Path.ChangeExtension(Rmdtoc.rmdtocStream.Name, null) + "-" + info.FileIndex.ToString("D3") + ".rmdblob"; - Console.WriteLine(path); - var stream = new FStream(path, FileMode.Open, FileAccess.ReadWrite); + var stream = new FStream(GetRMDBLOBPath(info), FileMode.Open, FileAccess.ReadWrite); - info.BufferUSize = NewFileBytes.Length; - var CompressedBytes = LZ4Codec.Encode(NewFileBytes, 0, info.BufferUSize); - info.BufferSize = CompressedBytes.Length; + byte[] CompressedBytes; + if (info.isCompressed != 0) + { + info.BufferUSize = NewFileBytes.Length; + CompressedBytes = LZ4Codec.Encode(NewFileBytes, 0, info.BufferUSize); + info.BufferSize = CompressedBytes.Length; + } + else + { + info.BufferUSize = NewFileBytes.Length; + CompressedBytes = NewFileBytes; + info.BufferSize = 0; + } + + ///// stream.Seek(0, SeekOrigin.End); info.BufferOffset = (int)stream.Position; stream.SetBytes(CompressedBytes); + //////// - CompressInfos = new CompressInfo[1]; - CompressInfos[0] = info; - CompressionInfoTableSize = Marshal.SizeOf(); - DecompressSize = NewFileBytes.Length; + CompressInfos.Clear(); + CompressInfos.Add(info); + /// + CompressionInfoTableSize = CompressInfo.Size * CompressInfos.Count; + DecompressSize = info.BufferUSize; stream.Close(); IsEdited = false; @@ -263,22 +383,17 @@ public void SetFile() public class rmdtoc : IDisposable { - public IStream rmdtocStream; public rmdtocHeader header; - - - public rmdtoc(string rmdtocPath) { rmdtocStream = new FStream(rmdtocPath, System.IO.FileMode.Open, System.IO.FileAccess.ReadWrite); - - Load(); } public IStream BufferStream; + public IStream RMDBLOBPathBlock; public IStream Table1; public IStream Table2; public IStream Table3; @@ -287,24 +402,31 @@ public rmdtoc(string rmdtocPath) public IStream NameTable; public List Files; public List Folders; + public List RMDBLOBPaths; public TreeNode Root; void Load() { header = rmdtocStream.Get(); - BufferStream = new MStream(GetBuffer(rmdtocStream, header.CompressionInfoTableOffset, header.CompressionInfoTableSize)); + RMDBLOBPathBlock = new MStream(BufferStream.GetBytes(header.RMDBLOB_Path_Count * RMDBLOBPath.Size, SeekToOffset: header.RMDBLOB_Path_Offset)); Table1 = new MStream(BufferStream.GetBytes(header.Table_1_Count * 0x1C, SeekToOffset: header.Table_1_Offset)); Table2 = new MStream(BufferStream.GetBytes(header.Table_2_Count * 0x20, SeekToOffset: header.Table_2_Offset)); Table3 = new MStream(BufferStream.GetBytes(header.Table_3_Count * 0x8, SeekToOffset: header.Table_3_Offset)); Table4 = new MStream(BufferStream.GetBytes(header.Table_4_Size, SeekToOffset: header.Table_4_Offset)); Table5 = new MStream(BufferStream.GetBytes(header.Table_5_Size, SeekToOffset: header.Table_5_Offset)); - - - NameTable = new MStream(BufferStream.GetBytes(header.Names_Size, SeekToOffset: header.Names_Offset)); + RMDBLOBPaths=new List(); + for (int i = 0; i < header.RMDBLOB_Path_Count; i++) + { + var path = new RMDBLOBPath(); + path.Read(RMDBLOBPathBlock); + path.Path = GetName(path.NameOffset, path.NameLength); + RMDBLOBPaths.Add(path); + } + Files = new List(); for (int i = 0; i < header.Table_2_Count; i++) { @@ -312,7 +434,16 @@ void Load() file.Read(Table2); file.Rmdtoc = this; file.DMKPBlock = Table4.GetBytes(file.DMKPTableSize, false, file.DMKPTableOffset); - file.CompressInfos = Table5.GetArray(file.CompressionInfoTableSize / Marshal.SizeOf(), false, file.CompressionInfoTableOffset); + file.CompressInfos = new List(); + + Table5.Seek(file.CompressionInfoTableOffset); + for (int j = 0; j < file.CompressionInfoTableSize / CompressInfo.Size; j++) + { + var info = new CompressInfo(); + info.Read(Table5); + file.CompressInfos.Add(info); + } + file.Name = GetName(file.NameOffset, file.NameLength); Files.Add(file); } @@ -344,7 +475,7 @@ void Load() private void MakeNode(List folders, TreeNode node, FolderInfo Folder) { - for (int i = Folder.unko; i < Folder.unko + Folder.unko2; i++) + for (int i = Folder.FolderIndex; i < Folder.FolderIndex + Folder.FolderCount; i++) { Root = new TreeNode(folders[i].Name); Root.Tag = folders[i]; @@ -362,11 +493,16 @@ public byte[] GetBuffer(IStream stream, long offset, int BlockSize) var StoreOffset = stream.Position; stream.Position = offset; - for (int i = 0; i < BlockSize / Marshal.SizeOf(); i++) + for (int i = 0; i < BlockSize / CompressInfo.Size; i++) { - var info = stream.Get(); + var info = new CompressInfo(); + info.Read(stream); - DecompressBuffer.SetBytes(LZ4Codec.Decode(stream.GetBytes(info.BufferSize, false, info.BufferOffset), 0, info.BufferSize, info.BufferUSize)); + var pos = stream.Position; + stream.Seek(info.BufferOffset); + DecompressBuffer.SetBytes(LZ4Codec.Decode(stream.GetBytes(info.BufferSize), 0, info.BufferSize, info.BufferUSize)); + + stream.Position = pos; } stream.Position = StoreOffset; @@ -385,7 +521,7 @@ private CompressInfo[] CompressFile(byte[] bytes, out byte[] CompressedBytes) { var info = new List(); var compressinfo = new CompressInfo(); - compressinfo.unko = 0x10; + compressinfo.isCompressed = 0x10; compressinfo.BufferUSize = bytes.Length; CompressedBytes = LZ4Codec.Encode(bytes, 0, compressinfo.BufferUSize); compressinfo.BufferSize = CompressedBytes.Length; @@ -407,7 +543,7 @@ public void Save() file.CompressionInfoTableOffset = (int)Table5.Position; foreach (var info in file.CompressInfos) { - Table5.SetStructureValus(info); + info.Write(Table5); } } @@ -417,8 +553,12 @@ public void Save() file.Write(Table2); } - BufferStream.SetSize(header.Table_1_Offset); - BufferStream.SetPosition(header.Table_1_Offset); + BufferStream = new MStream(); + + header.RMDBLOB_Path_Offset = (int)BufferStream.Position; + BufferStream.SetBytes(RMDBLOBPathBlock.ToArray()); + + header.Table_1_Offset=(int)BufferStream.Position; BufferStream.SetBytes(Table1.ToArray()); header.Table_2_Offset = (int)BufferStream.Position; @@ -431,9 +571,11 @@ public void Save() BufferStream.SetBytes(Table3.ToArray()); header.Table_4_Offset = (int)BufferStream.Position; + header.Table_4_Size = (int)Table4.GetSize(); BufferStream.SetBytes(Table4.ToArray()); header.Table_5_Offset = (int)BufferStream.Position; + header.Table_5_Size = (int)Table5.GetSize(); BufferStream.SetBytes(Table5.ToArray()); @@ -448,7 +590,7 @@ public void Save() rmdtocStream.Seek(0); rmdtocStream.SetBytes(new byte[4096], false); - header.CompressionInfoTableSize = infoTable.Length * Marshal.SizeOf(); + header.CompressionInfoTableSize = infoTable.Length * CompressInfo.Size; rmdtocStream.SetStructureValus(header); @@ -456,7 +598,7 @@ public void Save() for (int i = 0; i < infoTable.Length; i++) { infoTable[i].BufferOffset = offset; - rmdtocStream.SetStructureValus(infoTable[i]); + infoTable[i].Write(rmdtocStream); offset += infoTable[i].BufferSize; } diff --git a/Forms/FrmMain.Designer.cs b/Forms/FrmMain.Designer.cs index 464625c..6b9f3ab 100644 --- a/Forms/FrmMain.Designer.cs +++ b/Forms/FrmMain.Designer.cs @@ -49,11 +49,14 @@ private void InitializeComponent() this.toolsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.stringTableEditorToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.exportRowToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.treeView1 = new Controls.NTreeView(); this.listView1 = new Controls.NListView(); this.FileName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.Offset = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); this.Size = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.RMDBLOBPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.imageViewerToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.contextMenuStrip1.SuspendLayout(); this.statusStrip1.SuspendLayout(); this.menuStrip1.SuspendLayout(); @@ -73,9 +76,10 @@ private void InitializeComponent() // this.contextMenuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { this.eportSelectedToolStripMenuItem, - this.replaceSelectedFileToolStripMenuItem}); + this.replaceSelectedFileToolStripMenuItem, + this.exportRowToolStripMenuItem}); this.contextMenuStrip1.Name = "contextMenuStrip1"; - this.contextMenuStrip1.Size = new System.Drawing.Size(181, 48); + this.contextMenuStrip1.Size = new System.Drawing.Size(230, 70); // // eportSelectedToolStripMenuItem // @@ -181,7 +185,8 @@ private void InitializeComponent() // toolsToolStripMenuItem // this.toolsToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { - this.stringTableEditorToolStripMenuItem}); + this.stringTableEditorToolStripMenuItem, + this.imageViewerToolStripMenuItem}); this.toolsToolStripMenuItem.Name = "toolsToolStripMenuItem"; this.toolsToolStripMenuItem.Size = new System.Drawing.Size(46, 24); this.toolsToolStripMenuItem.Text = "Tools"; @@ -210,6 +215,17 @@ private void InitializeComponent() this.splitContainer1.SplitterDistance = 264; this.splitContainer1.TabIndex = 2; // + // exportRowToolStripMenuItem + // + this.exportRowToolStripMenuItem.Name = "exportRowToolStripMenuItem"; + this.exportRowToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.Alt) + | System.Windows.Forms.Keys.Shift) + | System.Windows.Forms.Keys.T))); + this.exportRowToolStripMenuItem.Size = new System.Drawing.Size(229, 22); + this.exportRowToolStripMenuItem.Text = "Export Row"; + this.exportRowToolStripMenuItem.Visible = false; + this.exportRowToolStripMenuItem.Click += new System.EventHandler(this.exportRowToolStripMenuItem_Click); + // // treeView1 // this.treeView1.BackColor = System.Drawing.SystemColors.Window; @@ -238,7 +254,8 @@ private void InitializeComponent() this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { this.FileName, this.Offset, - this.Size}); + this.Size, + this.RMDBLOBPath}); this.listView1.ContextMenuStrip = this.contextMenuStrip1; this.listView1.Font = new System.Drawing.Font("Tahoma", 10F); this.listView1.HideSelection = false; @@ -268,6 +285,17 @@ private void InitializeComponent() this.Size.Text = "Size"; this.Size.Width = 193; // + // RMDBLOBPath + // + this.RMDBLOBPath.Text = "RMDBLOB Archive Path"; + // + // imageViewerToolStripMenuItem + // + this.imageViewerToolStripMenuItem.Name = "imageViewerToolStripMenuItem"; + this.imageViewerToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.imageViewerToolStripMenuItem.Text = "Image Viewer"; + this.imageViewerToolStripMenuItem.Click += new System.EventHandler(this.imageViewerToolStripMenuItem_Click); + // // FrmMain // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -321,6 +349,9 @@ private void TreeView1_BeforeClear(object sender, System.EventArgs e) private System.Windows.Forms.ToolStripMenuItem replaceSelectedFileToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem saveToolStripMenuItem; private System.Windows.Forms.ToolStripStatusLabel toolStripStatusLabel1; + private System.Windows.Forms.ToolStripMenuItem exportRowToolStripMenuItem; + private System.Windows.Forms.ColumnHeader RMDBLOBPath; + private System.Windows.Forms.ToolStripMenuItem imageViewerToolStripMenuItem; } } diff --git a/Forms/FrmMain.cs b/Forms/FrmMain.cs index 0865df6..b34198c 100644 --- a/Forms/FrmMain.cs +++ b/Forms/FrmMain.cs @@ -166,16 +166,62 @@ private void listView1_DoubleClick(object sender, EventArgs e) if (fileInfo.Name == "string_table.bin" || fileInfo.GetId() == "RMDL") { - var MStream = new MStream(fileInfo.GetFile()); + var MStream = new MStream(fileInfo.Name, fileInfo.GetFile()); var frm = new FrmStringTable(MStream); if (frm.ShowDialog() == DialogResult.OK) { - fileInfo.IsEdited = true; - fileInfo.NewFileBytes = MStream.ToArray(); - Modifiedtrmdtoc.Add(fileInfo.Rmdtoc); - MessageBox.Show("Done!"); + try + { + fileInfo.IsEdited = true; + fileInfo.NewFileBytes = MStream.ToArray(); + Modifiedtrmdtoc.Add(fileInfo.Rmdtoc); + MessageBox.Show("Done!"); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } } } + else if (fileInfo.Name.EndsWith(".png", StringComparison.InvariantCulture) || + fileInfo.Name.EndsWith(".jpg", StringComparison.InvariantCulture) || + fileInfo.Name.EndsWith(".bmp", StringComparison.InvariantCulture) || + fileInfo.Name.EndsWith(".tga", StringComparison.InvariantCulture) || + fileInfo.Name.EndsWith(".dds", StringComparison.InvariantCulture) || + fileInfo.Name.EndsWith(".tex", StringComparison.InvariantCulture)) + { + try + { + var MStream = new MStream(fileInfo.Name, fileInfo.GetFile()); + var frm = new frmImageViewer(MStream); + frm.ShowDialog(); + } + catch (Exception ex) + { + MessageBox.Show(ex.Message); + } + } + + + } + + private void exportRowToolStripMenuItem_Click(object sender, EventArgs e) + { + FolderDialog folderDialog = new FolderDialog(); + if (folderDialog.ShowDialog() != DialogResult.OK) + return; + foreach (ListViewItem item in listView1.SelectedItems) + { + var fileInfo = item.Tag as FileInfo; + File.WriteAllBytes(Path.Combine(folderDialog.FileName, fileInfo.Name), fileInfo.GetRow()); + } + + MessageBox.Show("Done!"); + } + + private void imageViewerToolStripMenuItem_Click(object sender, EventArgs e) + { + new frmImageViewer().Show(); } } } diff --git a/Forms/FrmMain.resx b/Forms/FrmMain.resx index 9bbd0a4..f0b684c 100644 --- a/Forms/FrmMain.resx +++ b/Forms/FrmMain.resx @@ -125,7 +125,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC4 - BwAAAk1TRnQBSQFMAwEBAAFwAQEBcAEBARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA + BwAAAk1TRnQBSQFMAwEBAAFAAQIBQAECARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA AUADAAEQAwABAQEAAQgGAAEEGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHAAdwBwAEA AfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANCAQADOQEA AYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/ATMDAAFm @@ -172,7 +172,7 @@ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0 ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAAC0 - BwAAAk1TRnQBSQFMAwEBAAFsAQEBbAEBARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA + BwAAAk1TRnQBSQFMAwEBAAE8AQIBPAECARABAAEQAQAE/wEJAQAI/wFCAU0BNgEEBgABNgEEAgABKAMA AUADAAEQAwABAQEAAQgGAAEEGAABgAIAAYADAAKAAQABgAMAAYABAAGAAQACgAIAA8ABAAHAAdwBwAEA AfABygGmAQABMwUAATMBAAEzAQABMwEAAjMCAAMWAQADHAEAAyIBAAMpAQADVQEAA00BAANCAQADOQEA AYABfAH/AQACUAH/AQABkwEAAdYBAAH/AewBzAEAAcYB1gHvAQAB1gLnAQABkAGpAa0CAAH/ATMDAAFm diff --git a/Forms/FrmStringTable.Designer.cs b/Forms/FrmStringTable.Designer.cs index e1d3914..1474a82 100644 --- a/Forms/FrmStringTable.Designer.cs +++ b/Forms/FrmStringTable.Designer.cs @@ -34,10 +34,19 @@ private void InitializeComponent() this.saveToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.toolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.exportAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.namesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.valuesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.bothToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); this.importAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.namesToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.valuesToolStripMenuItem1 = new System.Windows.Forms.ToolStripMenuItem(); + this.bothToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.dataGridView1 = new System.Windows.Forms.DataGridView(); this.TableName = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.TableValue = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.searchBox1 = new Controls.SearchBox(); + this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator(); + this.findToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.menuStrip1.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).BeginInit(); this.SuspendLayout(); @@ -66,7 +75,7 @@ private void InitializeComponent() // this.openToolStripMenuItem.Name = "openToolStripMenuItem"; this.openToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O))); - this.openToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.openToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.openToolStripMenuItem.Text = "Open"; this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); // @@ -75,7 +84,7 @@ private void InitializeComponent() this.saveToolStripMenuItem.Enabled = false; this.saveToolStripMenuItem.Name = "saveToolStripMenuItem"; this.saveToolStripMenuItem.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.S))); - this.saveToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.saveToolStripMenuItem.Size = new System.Drawing.Size(146, 22); this.saveToolStripMenuItem.Text = "Save"; this.saveToolStripMenuItem.Click += new System.EventHandler(this.saveToolStripMenuItem_Click); // @@ -83,7 +92,9 @@ private void InitializeComponent() // this.toolToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { this.exportAllToolStripMenuItem, - this.importAllToolStripMenuItem}); + this.importAllToolStripMenuItem, + this.toolStripSeparator1, + this.findToolStripMenuItem}); this.toolToolStripMenuItem.Enabled = false; this.toolToolStripMenuItem.Name = "toolToolStripMenuItem"; this.toolToolStripMenuItem.Size = new System.Drawing.Size(41, 20); @@ -91,18 +102,68 @@ private void InitializeComponent() // // exportAllToolStripMenuItem // + this.exportAllToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.namesToolStripMenuItem, + this.valuesToolStripMenuItem, + this.bothToolStripMenuItem1}); this.exportAllToolStripMenuItem.Name = "exportAllToolStripMenuItem"; - this.exportAllToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.exportAllToolStripMenuItem.Size = new System.Drawing.Size(127, 22); this.exportAllToolStripMenuItem.Text = "Export All"; this.exportAllToolStripMenuItem.Click += new System.EventHandler(this.exportAllToolStripMenuItem_Click); // + // namesToolStripMenuItem + // + this.namesToolStripMenuItem.Name = "namesToolStripMenuItem"; + this.namesToolStripMenuItem.Size = new System.Drawing.Size(111, 22); + this.namesToolStripMenuItem.Text = "Names"; + this.namesToolStripMenuItem.Click += new System.EventHandler(this.namesToolStripMenuItem_Click); + // + // valuesToolStripMenuItem + // + this.valuesToolStripMenuItem.Name = "valuesToolStripMenuItem"; + this.valuesToolStripMenuItem.Size = new System.Drawing.Size(111, 22); + this.valuesToolStripMenuItem.Text = "Values"; + this.valuesToolStripMenuItem.Click += new System.EventHandler(this.valuesToolStripMenuItem_Click); + // + // bothToolStripMenuItem1 + // + this.bothToolStripMenuItem1.Name = "bothToolStripMenuItem1"; + this.bothToolStripMenuItem1.Size = new System.Drawing.Size(111, 22); + this.bothToolStripMenuItem1.Text = "Both"; + this.bothToolStripMenuItem1.Click += new System.EventHandler(this.bothToolStripMenuItem1_Click); + // // importAllToolStripMenuItem // + this.importAllToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.namesToolStripMenuItem1, + this.valuesToolStripMenuItem1, + this.bothToolStripMenuItem}); this.importAllToolStripMenuItem.Name = "importAllToolStripMenuItem"; - this.importAllToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.importAllToolStripMenuItem.Size = new System.Drawing.Size(127, 22); this.importAllToolStripMenuItem.Text = "Import All"; this.importAllToolStripMenuItem.Click += new System.EventHandler(this.importAllToolStripMenuItem_Click); // + // namesToolStripMenuItem1 + // + this.namesToolStripMenuItem1.Name = "namesToolStripMenuItem1"; + this.namesToolStripMenuItem1.Size = new System.Drawing.Size(111, 22); + this.namesToolStripMenuItem1.Text = "Names"; + this.namesToolStripMenuItem1.Click += new System.EventHandler(this.namesToolStripMenuItem1_Click); + // + // valuesToolStripMenuItem1 + // + this.valuesToolStripMenuItem1.Name = "valuesToolStripMenuItem1"; + this.valuesToolStripMenuItem1.Size = new System.Drawing.Size(111, 22); + this.valuesToolStripMenuItem1.Text = "Values"; + this.valuesToolStripMenuItem1.Click += new System.EventHandler(this.valuesToolStripMenuItem1_Click); + // + // bothToolStripMenuItem + // + this.bothToolStripMenuItem.Name = "bothToolStripMenuItem"; + this.bothToolStripMenuItem.Size = new System.Drawing.Size(111, 22); + this.bothToolStripMenuItem.Text = "Both"; + this.bothToolStripMenuItem.Click += new System.EventHandler(this.bothToolStripMenuItem_Click); + // // dataGridView1 // this.dataGridView1.AllowUserToAddRows = false; @@ -114,9 +175,10 @@ private void InitializeComponent() this.dataGridView1.Dock = System.Windows.Forms.DockStyle.Fill; this.dataGridView1.Location = new System.Drawing.Point(0, 24); this.dataGridView1.Name = "dataGridView1"; - this.dataGridView1.Size = new System.Drawing.Size(801, 524); + this.dataGridView1.Size = new System.Drawing.Size(801, 494); this.dataGridView1.TabIndex = 1; this.dataGridView1.CellValueChanged += new System.Windows.Forms.DataGridViewCellEventHandler(this.dataGridView1_CellValueChanged); + this.dataGridView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.dataGridView1_KeyDown); // // TableName // @@ -129,6 +191,28 @@ private void InitializeComponent() this.TableValue.HeaderText = "Text Value"; this.TableValue.Name = "TableValue"; // + // searchBox1 + // + this.searchBox1.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle; + this.searchBox1.DataGridView = this.dataGridView1; + this.searchBox1.Dock = System.Windows.Forms.DockStyle.Bottom; + this.searchBox1.Location = new System.Drawing.Point(0, 518); + this.searchBox1.Name = "searchBox1"; + this.searchBox1.Size = new System.Drawing.Size(801, 30); + this.searchBox1.TabIndex = 2; + // + // toolStripSeparator1 + // + this.toolStripSeparator1.Name = "toolStripSeparator1"; + this.toolStripSeparator1.Size = new System.Drawing.Size(177, 6); + // + // findToolStripMenuItem + // + this.findToolStripMenuItem.Name = "findToolStripMenuItem"; + this.findToolStripMenuItem.Size = new System.Drawing.Size(180, 22); + this.findToolStripMenuItem.Text = "Find"; + this.findToolStripMenuItem.Click += new System.EventHandler(this.findToolStripMenuItem_Click); + // // FrmStringTable // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -136,10 +220,12 @@ private void InitializeComponent() this.ClientSize = new System.Drawing.Size(801, 548); this.Controls.Add(this.dataGridView1); this.Controls.Add(this.menuStrip1); + this.Controls.Add(this.searchBox1); this.MainMenuStrip = this.menuStrip1; this.Name = "FrmStringTable"; this.ShowIcon = false; this.Text = "String Table Editor"; + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FrmStringTable_KeyDown); this.menuStrip1.ResumeLayout(false); this.menuStrip1.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView1)).EndInit(); @@ -160,5 +246,14 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem toolToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem exportAllToolStripMenuItem; private System.Windows.Forms.ToolStripMenuItem importAllToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem namesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem valuesToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem namesToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem valuesToolStripMenuItem1; + private System.Windows.Forms.ToolStripMenuItem bothToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem bothToolStripMenuItem1; + private Controls.SearchBox searchBox1; + private System.Windows.Forms.ToolStripSeparator toolStripSeparator1; + private System.Windows.Forms.ToolStripMenuItem findToolStripMenuItem; } } \ No newline at end of file diff --git a/Forms/FrmStringTable.cs b/Forms/FrmStringTable.cs index ca8297f..7f19eb4 100644 --- a/Forms/FrmStringTable.cs +++ b/Forms/FrmStringTable.cs @@ -113,6 +113,15 @@ private void saveToolStripMenuItem_Click(object sender, EventArgs e) } private void exportAllToolStripMenuItem_Click(object sender, EventArgs e) + { + + } + + private void importAllToolStripMenuItem_Click(object sender, EventArgs e) + { + } + + private void namesToolStripMenuItem_Click(object sender, EventArgs e) { var sdf = new SaveFileDialog(); sdf.Filter = "Text Files|*.txt"; @@ -124,7 +133,7 @@ private void exportAllToolStripMenuItem_Click(object sender, EventArgs e) var sb = new System.Text.StringBuilder(); foreach (var Table in stringtable as List) { - sb.AppendLine(Table.Name + "=" + Table.Value); + sb.AppendLine(Table.Name); } File.WriteAllText(sdf.FileName, sb.ToString()); @@ -132,7 +141,71 @@ private void exportAllToolStripMenuItem_Click(object sender, EventArgs e) MessageBox.Show("Done!"); } - private void importAllToolStripMenuItem_Click(object sender, EventArgs e) + private void valuesToolStripMenuItem_Click(object sender, EventArgs e) + { + var sdf = new SaveFileDialog(); + sdf.Filter = "Text Files|*.txt"; + sdf.Title = "Save Text File"; + sdf.FileName = Path.GetFileName(Stream.Name) + ".txt"; + if (sdf.ShowDialog() != DialogResult.OK) + return; + + var sb = new System.Text.StringBuilder(); + foreach (var Table in stringtable as List) + { + sb.AppendLine(Table.Value); + } + + File.WriteAllText(sdf.FileName, sb.ToString()); + + MessageBox.Show("Done!"); + } + + private void namesToolStripMenuItem1_Click(object sender, EventArgs e) + { + var ofd = new OpenFileDialog(); + ofd.Filter = "Text Files|*.txt"; + ofd.Title = "Select Text File"; + ofd.FileName = Path.GetFileName(Stream.Name) + ".txt"; + if (ofd.ShowDialog() != DialogResult.OK) + return; + + var lines = File.ReadAllLines(ofd.FileName); + int i = 0; + foreach (var line in lines) + { + if (i >= dataGridView1.Rows.Count) break; + var Table = dataGridView1.Rows[i++]; + Table.Cells["TableName"].Value = line; + } + + MessageBox.Show("Done!"); + } + + private void valuesToolStripMenuItem1_Click(object sender, EventArgs e) + { + var ofd = new OpenFileDialog(); + ofd.Filter = "Text Files|*.txt"; + ofd.Title = "Select Text File"; + ofd.FileName = Path.GetFileName(Stream.Name) + ".txt"; + if (ofd.ShowDialog() != DialogResult.OK) + return; + + var lines = File.ReadAllLines(ofd.FileName); + int i = 0; + foreach (var line in lines) + { + if (i >= dataGridView1.Rows.Count) break; + + var Table = dataGridView1.Rows[i++]; + Table.Cells["TableValue"].Value = line; + + } + + MessageBox.Show("Done!"); + } + + private void bothToolStripMenuItem_Click(object sender, EventArgs e) { var ofd = new OpenFileDialog(); ofd.Filter = "Text Files|*.txt"; @@ -145,7 +218,8 @@ private void importAllToolStripMenuItem_Click(object sender, EventArgs e) int i = 0; foreach (var line in lines) { - var split = line.Split(new[] { '=' },2); + if (i >= dataGridView1.Rows.Count) break; + var split = line.Split(new[] { '=' }, 2); if (split.Length != 2) continue; @@ -157,11 +231,41 @@ private void importAllToolStripMenuItem_Click(object sender, EventArgs e) Table.Cells["TableValue"].Value = value; } - MessageBox.Show("Done!"); + } + private void bothToolStripMenuItem1_Click(object sender, EventArgs e) + { + var sdf = new SaveFileDialog(); + sdf.Filter = "Text Files|*.txt"; + sdf.Title = "Save Text File"; + sdf.FileName = Path.GetFileName(Stream.Name) + ".txt"; + if (sdf.ShowDialog() != DialogResult.OK) + return; + var sb = new System.Text.StringBuilder(); + foreach (var Table in stringtable as List) + { + sb.AppendLine(Table.Name+"="+ Table.Value); + } + } + private void FrmStringTable_KeyDown(object sender, KeyEventArgs e) + { + + } + + private void dataGridView1_KeyDown(object sender, KeyEventArgs e) + { + if (e.Control && e.KeyCode == Keys.F) + { + searchBox1.Visible = true; + } + } + + private void findToolStripMenuItem_Click(object sender, EventArgs e) + { + searchBox1.Visible = true; } } } diff --git a/Forms/FrmStringTable.resx b/Forms/FrmStringTable.resx index 87c5092..0210eaa 100644 --- a/Forms/FrmStringTable.resx +++ b/Forms/FrmStringTable.resx @@ -126,4 +126,10 @@ True + + True + + + True + \ No newline at end of file diff --git a/Forms/frmImageViewer.Designer.cs b/Forms/frmImageViewer.Designer.cs new file mode 100644 index 0000000..06c82cd --- /dev/null +++ b/Forms/frmImageViewer.Designer.cs @@ -0,0 +1,102 @@ +namespace alan_wake_2_rmdtoc_Tool.Forms +{ + partial class frmImageViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); + this.fileToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.openToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.menuStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // menuStrip1 + // + this.menuStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.fileToolStripMenuItem}); + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Padding = new System.Windows.Forms.Padding(0); + this.menuStrip1.Size = new System.Drawing.Size(800, 24); + this.menuStrip1.TabIndex = 0; + this.menuStrip1.Text = "menuStrip1"; + // + // fileToolStripMenuItem + // + this.fileToolStripMenuItem.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.openToolStripMenuItem}); + this.fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + this.fileToolStripMenuItem.Size = new System.Drawing.Size(37, 20); + this.fileToolStripMenuItem.Text = "File"; + // + // openToolStripMenuItem + // + this.openToolStripMenuItem.Name = "openToolStripMenuItem"; + this.openToolStripMenuItem.Size = new System.Drawing.Size(103, 22); + this.openToolStripMenuItem.Text = "Open"; + this.openToolStripMenuItem.Click += new System.EventHandler(this.openToolStripMenuItem_Click); + // + // pictureBox1 + // + this.pictureBox1.Dock = System.Windows.Forms.DockStyle.Fill; + this.pictureBox1.Location = new System.Drawing.Point(0, 24); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(800, 426); + this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.pictureBox1.TabIndex = 1; + this.pictureBox1.TabStop = false; + // + // frmImageViewer + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.SystemColors.ButtonShadow; + this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.pictureBox1); + this.Controls.Add(this.menuStrip1); + this.MainMenuStrip = this.menuStrip1; + this.Name = "frmImageViewer"; + this.ShowIcon = false; + this.Text = "Image Viwer"; + this.menuStrip1.ResumeLayout(false); + this.menuStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.MenuStrip menuStrip1; + private System.Windows.Forms.ToolStripMenuItem fileToolStripMenuItem; + private System.Windows.Forms.ToolStripMenuItem openToolStripMenuItem; + private System.Windows.Forms.PictureBox pictureBox1; + } +} \ No newline at end of file diff --git a/Forms/frmImageViewer.cs b/Forms/frmImageViewer.cs new file mode 100644 index 0000000..ae43b39 --- /dev/null +++ b/Forms/frmImageViewer.cs @@ -0,0 +1,58 @@ +using Helper; +using System; +using System.IO; +using System.Windows.Forms; + +namespace alan_wake_2_rmdtoc_Tool.Forms +{ + public partial class frmImageViewer : Form + { + bool IsStreamFile = false; + public IStream Stream; + public frmImageViewer() + { + InitializeComponent(); + } + + public frmImageViewer(IStream stream) + { + + InitializeComponent(); + Stream = stream; + IsStreamFile = false; + openToolStripMenuItem.Visible = false; + PrintImage(); + } + + private void openToolStripMenuItem_Click(object sender, EventArgs e) + { + var ofd = new OpenFileDialog(); + ofd.Filter = "All Images|*.tex;*.dds;*.png;*.jpg;*.bmp;*.tga"; + ofd.Title = "Select Image"; + if (ofd.ShowDialog() != DialogResult.OK) + return; + + Stream = FStream.Open(ofd.FileName, FileMode.Open, FileAccess.Read); + PrintImage(); + } + + private void PrintImage() + { + if (Stream.GetIntValue(false) == 0x20534444) + { + pictureBox1.Image = DDSToBitmap.Convert(Stream); + } + else if (Stream.Name.EndsWith(".png", StringComparison.InvariantCulture) || + Stream.Name.EndsWith(".jpg", StringComparison.InvariantCulture) || + Stream.Name.EndsWith(".bmp", StringComparison.InvariantCulture) || + Stream.Name.EndsWith(".tga", StringComparison.InvariantCulture)) + { + pictureBox1.Image = System.Drawing.Image.FromStream((Stream)Stream); + } + else + { + MessageBox.Show("Not supported file!"); + } + } + } +} diff --git a/Forms/frmImageViewer.resx b/Forms/frmImageViewer.resx new file mode 100644 index 0000000..d5494e3 --- /dev/null +++ b/Forms/frmImageViewer.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Helper/DDSCooker.cs b/Helper/DDSCooker.cs new file mode 100644 index 0000000..0ce10a7 --- /dev/null +++ b/Helper/DDSCooker.cs @@ -0,0 +1,1038 @@ +using System; +using System.ComponentModel; +using System.Runtime.InteropServices; +using System.Text; + + +namespace Helper +{ + + public enum DDSFormat : uint + { + unknown = 0, + r32g32b32a32_typeless, + r32g32b32a32_float, + r32g32b32a32_uint, + r32g32b32a32_sint, + r32g32b32_typeless, + r32g32b32_float, + r32g32b32_uint, + r32g32b32_sint, + r16g16b16a16_typeless, + r16g16b16a16_float, + r16g16b16a16_unorm, + r16g16b16a16_uint, + r16g16b16a16_snorm, + r16g16b16a16_sint, + r32g32_typeless, + r32g32_float, + r32g32_uint, + r32g32_sint, + r32g8x24_typeless, + d32_float_s8x24_uint, + r32_float_x8x24_typeless, + x32_typeless_g8x24_uint, + r10g10b10a2_typeless, + r10g10b10a2_unorm, + r10g10b10a2_uint, + r11g11b10_float, + r8g8b8a8_typeless, + r8g8b8a8_unorm, + r8g8b8a8_unorm_srgb, + r8g8b8a8_uint, + r8g8b8a8_snorm, + r8g8b8a8_sint, + r16g16_typeless, + r16g16_float, + r16g16_unorm, + r16g16_uint, + r16g16_snorm, + r16g16_sint, + r32_typeless, + d32_float, + r32_float, + r32_uint, + r32_sint, + r24g8_typeless, + d24_unorm_s8_uint, + r24_unorm_x8_typeless, + x24_typeless_g8_uint, + r8g8_typeless, + [Description("A8L8")] + r8g8_unorm, + r8g8_uint, + [Description("V8U8")] + r8g8_snorm, + r8g8_sint, + r16_typeless, + r16_float, + d16_unorm, + r16_unorm, + r16_uint, + r16_snorm, + r16_sint, + r8_typeless, + [Description("L8")] + r8_unorm, + r8_uint, + r8_snorm, + r8_sint, + [Description("A8")] + a8_unorm, + r1_unorm, + r9g9b9e5_sharedexp, + [Description("RGBG or GBGR")] + r8g8_b8g8_unorm, + g8r8_g8b8_unorm, + bc1_typeless, + [Description("DXT1")] + bc1_unorm, + [Description("DXT1")] + bc1_unorm_srgb, + bc2_typeless, + [Description("DXT2")] + bc2_unorm, + [Description("DXT2")] + bc2_unorm_srgb, + bc3_typeless, + [Description("DXT5")] + bc3_unorm, + [Description("DXT5")] + bc3_unorm_srgb, + bc4_typeless, + [Description("BC4U")] + bc4_unorm, + [Description("BC4S")] + bc4_snorm, + bc5_typeless, + [Description("ATI2 or BC5U")] + bc5_unorm, + [Description("BC5S")] + bc5_snorm, + b5g6r5_unorm, + [Description("B5G5R5A1 A1R5G5B5")] + b5g5r5a1_unorm, + [Description("A8R8G8B8")] + b8g8r8a8_unorm, + [Description("X8R8G8B8")] + b8g8r8x8_unorm, + r10g10b10_xr_bias_a2_unorm, + b8g8r8a8_typeless, + [Description("A8B8G8R8")] + b8g8r8a8_unorm_srgb, + b8g8r8x8_typeless, + [Description("X8B8G8R8")] + b8g8r8x8_unorm_srgb, + bc6h_typeless, + bc6h_uf16, + bc6h_sf16, + bc7_typeless, + bc7_unorm, + bc7_unorm_srgb, + ayuv, + y410, + y416, + nv12, + p010, + p016, + opaque, + [Description("YUY2")] + yuy2, + y210, + y216, + nv11, + ai44, + ia44, + p8, + a8p8, + [Description("A4R4G4B4")] + b4g4r4a4_unorm, + p208, + v208, + v408 + } + public static class DDSCooker //Todo + { + + + + public static uint BitsPerPixel(DDSFormat fmt) + { + switch (fmt) + { + case DDSFormat.r32g32b32a32_typeless: + case DDSFormat.r32g32b32a32_float: + case DDSFormat.r32g32b32a32_uint: + case DDSFormat.r32g32b32a32_sint: + return 128; + + case DDSFormat.r32g32b32_typeless: + case DDSFormat.r32g32b32_float: + case DDSFormat.r32g32b32_uint: + case DDSFormat.r32g32b32_sint: + return 96; + + case DDSFormat.r16g16b16a16_typeless: + case DDSFormat.r16g16b16a16_float: + case DDSFormat.r16g16b16a16_unorm: + case DDSFormat.r16g16b16a16_uint: + case DDSFormat.r16g16b16a16_snorm: + case DDSFormat.r16g16b16a16_sint: + case DDSFormat.r32g32_typeless: + case DDSFormat.r32g32_float: + case DDSFormat.r32g32_uint: + case DDSFormat.r32g32_sint: + case DDSFormat.r32g8x24_typeless: + case DDSFormat.d32_float_s8x24_uint: + case DDSFormat.r32_float_x8x24_typeless: + case DDSFormat.x32_typeless_g8x24_uint: + return 64; + + case DDSFormat.r10g10b10a2_typeless: + case DDSFormat.r10g10b10a2_unorm: + case DDSFormat.r10g10b10a2_uint: + case DDSFormat.r11g11b10_float: + case DDSFormat.r8g8b8a8_typeless: + case DDSFormat.r8g8b8a8_unorm: + case DDSFormat.r8g8b8a8_unorm_srgb: + case DDSFormat.r8g8b8a8_uint: + case DDSFormat.r8g8b8a8_snorm: + case DDSFormat.r8g8b8a8_sint: + case DDSFormat.r16g16_typeless: + case DDSFormat.r16g16_float: + case DDSFormat.r16g16_unorm: + case DDSFormat.r16g16_uint: + case DDSFormat.r16g16_snorm: + case DDSFormat.r16g16_sint: + case DDSFormat.r32_typeless: + case DDSFormat.d32_float: + case DDSFormat.r32_float: + case DDSFormat.r32_uint: + case DDSFormat.r32_sint: + case DDSFormat.r24g8_typeless: + case DDSFormat.d24_unorm_s8_uint: + case DDSFormat.r24_unorm_x8_typeless: + case DDSFormat.x24_typeless_g8_uint: + case DDSFormat.r9g9b9e5_sharedexp: + case DDSFormat.r8g8_b8g8_unorm: + case DDSFormat.g8r8_g8b8_unorm: + case DDSFormat.b8g8r8a8_unorm: + case DDSFormat.b8g8r8x8_unorm: + case DDSFormat.r10g10b10_xr_bias_a2_unorm: + case DDSFormat.b8g8r8a8_typeless: + case DDSFormat.b8g8r8a8_unorm_srgb: + case DDSFormat.b8g8r8x8_typeless: + case DDSFormat.b8g8r8x8_unorm_srgb: + return 32; + + case DDSFormat.r8g8_typeless: + case DDSFormat.r8g8_unorm: + case DDSFormat.r8g8_uint: + case DDSFormat.r8g8_snorm: + case DDSFormat.r8g8_sint: + case DDSFormat.r16_typeless: + case DDSFormat.r16_float: + case DDSFormat.d16_unorm: + case DDSFormat.r16_unorm: + case DDSFormat.r16_uint: + case DDSFormat.r16_snorm: + case DDSFormat.r16_sint: + case DDSFormat.b5g6r5_unorm: + case DDSFormat.b5g5r5a1_unorm: + case DDSFormat.b4g4r4a4_unorm: + return 16; + + case DDSFormat.r8_typeless: + case DDSFormat.r8_unorm: + case DDSFormat.r8_uint: + case DDSFormat.r8_snorm: + case DDSFormat.r8_sint: + case DDSFormat.a8_unorm: + return 8; + + case DDSFormat.r1_unorm: + return 1; + + case DDSFormat.bc1_typeless: + case DDSFormat.bc1_unorm: + case DDSFormat.bc1_unorm_srgb: + case DDSFormat.bc4_typeless: + case DDSFormat.bc4_unorm: + case DDSFormat.bc4_snorm: + return 4; + + case DDSFormat.bc2_typeless: + case DDSFormat.bc2_unorm: + case DDSFormat.bc2_unorm_srgb: + case DDSFormat.bc3_typeless: + case DDSFormat.bc3_unorm: + case DDSFormat.bc3_unorm_srgb: + case DDSFormat.bc5_typeless: + case DDSFormat.bc5_unorm: + case DDSFormat.bc5_snorm: + case DDSFormat.bc6h_typeless: + case DDSFormat.bc6h_uf16: + case DDSFormat.bc6h_sf16: + case DDSFormat.bc7_typeless: + case DDSFormat.bc7_unorm: + case DDSFormat.bc7_unorm_srgb: + return 8; + + default: + return 0; + } + } + + + public static (uint, uint, uint, uint) GetMask(DDSFormat format) + { + switch (format) + { + //RGBBitCount=32 + case DDSFormat.r8g8b8a8_unorm: + return (0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000); + + case DDSFormat.r10g10b10a2_unorm: + return (0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000); + + case DDSFormat.r16g16_unorm: + return (0x0000ffff, 0xffff0000, 0x00000000, 0x00000000); + + case DDSFormat.r32_float: + return (0xffffffff, 0x00000000, 0x00000000, 0x00000000); + + case DDSFormat.b8g8r8a8_unorm: + return (0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); + + case DDSFormat.b8g8r8x8_unorm: + return (0x00ff0000, 0x0000ff00, 0x000000ff, 0); + + case DDSFormat.b8g8r8x8_unorm_srgb: + return (0x000000ff, 0x0000ff00, 0x00ff0000, 0); + + + + + //RGBBitCount=16 + case DDSFormat.b5g5r5a1_unorm: + return (0x7C00, 0x3E0, 0x1F, 0x8000); + case DDSFormat.b5g6r5_unorm: + return (0xf8000000, 0x07e00000, 0x001f0000, 0x00000000); + case DDSFormat.b4g4r4a4_unorm: + return (0x0f000000, 0x00f00000, 0x000f0000, 0xf0000000); + case DDSFormat.r16_unorm: + return (0x0000ffff, 0x00000000, 0x00000000, 0x00000000); + case DDSFormat.r8g8_unorm: + return (0xff, 0x00000000, 0x00000000, 0xFF00); + + + //RGBBitCount=8 + + case DDSFormat.r8_unorm: + return (0xff, 0x0, 0x0, 0x0); + + case DDSFormat.a8_unorm: + return (0x0, 0x0, 0x0, 0xff); + + default: + return (0x00000000, 0x00000000, 0x00000000, 0x00000000); + + + } + } + + + + + [Flags] + public enum DDSPixelFormatFlags + { + D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, + DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000 + } + + [Flags] + enum D3D10_RESOURCE_DIMENSION + { + D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, + D3D10_RESOURCE_DIMENSION_BUFFER = 1, + D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, + D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, + D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4 + } + + + [Flags] + public enum HeaderFlags + { + /// + /// Required in every .dds file. + /// + DDSD_CAPS = 0x1, + /// + /// Required in every .dds file. + /// + DDSD_HEIGHT = 0x2, + /// + /// Required in every .dds file. + /// + DDSD_WIDTH = 0x4, + /// + /// Required when pitch is provided for an uncompressed texture. + /// + DDSD_PITCH = 0x8, + /// + /// Required in every .dds file. + /// + DDSD_PIXELFORMAT = 0x1000, + /// + /// Required in a mipmapped texture. + /// + DDSD_MIPMAPCOUNT = 0x20000, + /// + /// Required when pitch is provided for a compressed texture. + /// + DDSD_LINEARSIZE = 0x80000, + /// + /// Required in a depth texture. + /// + DDSD_DEPTH = 0x800000 + } + + [Flags] + public enum DDSCAPS + { + /// + /// Optional; must be used on any file that contains more than one surface (a mipmap, a cubic environment map, or mipmapped volume texture). + /// + DDSCAPS_COMPLEX = 0x8, + /// + /// Required + /// + DDSCAPS_TEXTURE = 0x1000, + /// + /// Optional; should be used for a mipmap. + /// + DDSCAPS_MIPMAP = 0x400000 + } + + [Flags] + public enum DDSCAPS2 + { + /// + /// Required for a cube map. + /// + DDSCAPS2_CUBEMAP = 0x200, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + /// + /// Required when these surfaces are stored in a cube map. + /// + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + /// + /// Required for a volume texture. + /// + DDSCAPS2_VOLUME = 0x200000 + } + + + public enum DDPF + { + /// + /// Texture contains alpha data; dwRGBAlphaBitMask contains valid data. + /// + DDPF_ALPHAPIXELS = 0x1, + /// + /// Used in some older DDS files for alpha channel only uncompressed data (dwRGBBitCount contains the alpha channel bitcount; dwABitMask contains valid data) + /// + DDPF_ALPHA = 0x2, + /// + /// Texture contains compressed RGB data; dwFourCC contains valid data. + /// + DDPF_FOURCC = 0x4, + /// + /// Texture contains uncompressed RGB data; dwRGBBitCount and the RGB masks(dwRBitMask, dwGBitMask, dwBBitMask) contain valid data. + /// + DDPF_RGB = 0x40, + /// + /// Used in some older DDS files for YUV uncompressed data(dwRGBBitCount contains the YUV bit count; dwRBitMask contains the Y mask, dwGBitMask contains the U mask, dwBBitMask contains the V mask) + /// + DDPF_YUV = 0x200, + /// + /// Used in some older DDS files for single channel color uncompressed data(dwRGBBitCount contains the luminance channel bit count; dwRBitMask contains the channel mask). Can be combined with DDPF_ALPHAPIXELS for a two channel DDS file. + /// + DDPF_LUMINANCEA = 0x20001, //DDPF_LUMINANCE| DDPF_ALPHAPIXELS + DDPF_LUMINANCE = 0x20000, + + + DDPF_RGBA = 0x41, //DDPF_RGB | DDPF_ALPHAPIXELS + DDPF_PAL8 = 0x20, + DDPF_PAL8A = 0x21, //DDPF_PAL8 | DDPF_ALPHAPIXELS + DDPF_BUMPDUDV = 0x80000 + } + + enum DDS_DIMENSION + { + /// + /// (D3D10_RESOURCE_DIMENSION_TEXTURE1D) Resource is a 1D texture.The dwWidth member of DDS_HEADER specifies the size of the texture.Typically, you set the dwHeight member of DDS_HEADER to 1; you also must set the DDSD_HEIGHT flag in the dwFlags member of DDS_HEADER. + /// + DDS_DIMENSION_TEXTURE1D = 2, + /// + /// (D3D10_RESOURCE_DIMENSION_TEXTURE2D) Resource is a 2D texture with an area specified by the dwWidth and dwHeight members of DDS_HEADER.You can also use this type to identify a cube-map texture.For more information about how to identify a cube-map texture, see miscFlag and arraySize members. + /// + DDS_DIMENSION_TEXTURE2D = 3, + /// + /// (D3D10_RESOURCE_DIMENSION_TEXTURE3D) Resource is a 3D texture with a volume specified by the dwWidth, dwHeight, and dwDepth members of DDS_HEADER.You also must set the DDSD_DEPTH flag in the dwFlags member of DDS_HEADER. + /// + DDS_DIMENSION_TEXTURE3D = 4 + } + + + /// + /// Indicates a 2D texture is a cube-map texture. + /// + static uint DDS_RESOURCE_MISC_TEXTURECUBE = 0x4; + + + + enum DDS_ALPHA_MODE + { + /// + /// Alpha channel content is unknown. This is the value for legacy files, which typically is assumed to be 'straight' alpha. + /// + DDS_ALPHA_MODE_UNKNOWN = 0x0, + /// + /// Any alpha channel content is presumed to use straight alpha. + /// + DDS_ALPHA_MODE_STRAIGHT = 0x1, + /// + /// Any alpha channel content is using premultiplied alpha.The only legacy file formats that indicate this information are 'DX2' and 'DX4'. + /// + DDS_ALPHA_MODE_PREMULTIPLIED = 0x2, + /// + /// Any alpha channel content is all set to fully opaque. + /// + DDS_ALPHA_MODE_OPAQUE = 0x3, + /// + /// Any alpha channel content is being used as a 4th channel and is not intended to represent transparency (straight or premultiplied). + /// + DDS_ALPHA_MODE_CUSTOM = 0x4, + } + + + + + + + public static byte[] TexToDds(byte[] bytes, DDSFormat format, int height, int width, int mipmap = 0, int depth = 0, bool UseDX10 = false) + { + MStream Tex = new MStream(bytes); + Tex.SetStringValue("DDS "); + Tex.SetIntValue(124);//block size + HeaderFlags flags = HeaderFlags.DDSD_CAPS | HeaderFlags.DDSD_HEIGHT | HeaderFlags.DDSD_WIDTH | HeaderFlags.DDSD_PIXELFORMAT; + + + if (depth != 0) + { + flags |= HeaderFlags.DDSD_DEPTH; + } + + if (mipmap > 1) + { + flags |= HeaderFlags.DDSD_MIPMAPCOUNT; + } + + //if (format == Format.bc1_unorm || format == Format.bc2_unorm || format == Format.bc3_unorm) + //{ + // flags |= HeaderFlags.DDSD_LINEARSIZE; + //} + + Tex.SetUIntValue((uint)flags); + Tex.SetIntValue(height); + Tex.SetIntValue(width); + Tex.SetIntValue(0); //pitchOrLinearSize + Tex.SetIntValue(depth); + Tex.SetIntValue(mipmap); + + Tex.Skip(44); //reserved1 + + Tex.SetIntValue(32); //block size + DDPF dwFlags = 0; + if (format == DDSFormat.bc1_unorm || format == DDSFormat.bc2_unorm || format == DDSFormat.bc3_unorm || UseDX10) + { + dwFlags = DDPF.DDPF_FOURCC; + } + else if (format == DDSFormat.r8_unorm || format == DDSFormat.r16_unorm || format == DDSFormat.r8g8_unorm) + { + dwFlags = DDPF.DDPF_LUMINANCE; + } + else if (format == DDSFormat.a8_unorm) + { + dwFlags = DDPF.DDPF_ALPHA; + } + else + { + dwFlags = DDPF.DDPF_ALPHAPIXELS | DDPF.DDPF_RGB; + } + + // dwFlags// + Tex.SetUIntValue((uint)dwFlags); //block size + + bool ISDX10 = false; + if (format == DDSFormat.bc1_unorm) + { + Tex.SetStringValue("DXT1"); + } + else if (format == DDSFormat.bc2_unorm) + { + Tex.SetStringValue("DXT3"); + } + else if (format == DDSFormat.bc3_unorm) + { + Tex.SetStringValue("DXT5"); + } + else if (format == DDSFormat.bc4_unorm) + { + Tex.SetStringValue("ATI1"); + } + else if (format == DDSFormat.bc5_unorm) + { + Tex.SetStringValue("ATI2"); + } + else + { + if (!UseDX10) + { + Tex.SetIntValue(0); + } + else + { + Tex.SetStringValue("DX10"); + ISDX10 = true; + } + } + + uint RGBBitCount = 0; + uint RBitMask = 0; + uint GBitMask = 0; + uint BBitMask = 0; + uint ABitMask = 0; + + if (!ISDX10) + { + RGBBitCount = BitsPerPixel(format); + (RBitMask, GBitMask, BBitMask, ABitMask) = GetMask(format); + } + + Tex.SetUIntValue(RGBBitCount); //RGBBitCount + Tex.SetUIntValue(RBitMask); //RBitMask + Tex.SetUIntValue(GBitMask); //GBitMask + Tex.SetUIntValue(BBitMask); //BBitMask + Tex.SetUIntValue(ABitMask); //ABitMask + + DDSCAPS Caps = DDSCAPS.DDSCAPS_TEXTURE; + + if (mipmap > 1) + { + Caps |= DDSCAPS.DDSCAPS_MIPMAP; + } + + if (mipmap > 1 || depth > 1) + { + Caps |= DDSCAPS.DDSCAPS_COMPLEX; + } + + Tex.SetUIntValue((uint)Caps); + + DDSCAPS2 Caps2 = 0; + Tex.SetUIntValue((uint)Caps2); + Tex.SetUIntValue(0);//Caps3 + Tex.SetUIntValue(0);//Caps4 + Tex.SetUIntValue(0);//reserved2 + + if (ISDX10) + { + Tex.SetUIntValue((uint)format);//DXGI_FORMAT + Tex.SetUIntValue((uint)DDS_DIMENSION.DDS_DIMENSION_TEXTURE2D);//D3D10_RESOURCE_DIMENSION + Tex.SetUIntValue(0);//miscFlag + Tex.SetUIntValue(1);//arraySize //For a 3D texture, you must set this number to 1. + Tex.SetUIntValue((uint)DDS_ALPHA_MODE.DDS_ALPHA_MODE_UNKNOWN);//miscFlags2 + } + + Tex.SetBytes(bytes); + + return Tex.ToArray(); + } + + + + + public struct DDS_HEADER + { + public uint Magic; + public uint size; + [MarshalAs(UnmanagedType.U4)] + public HeaderFlags flags; + public int height; + public int width; + public int pitchOrLinearSize; + public int depth; + public int mipMapCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public uint[] reserved1; + public DDS_PIXELFORMAT ddspf; + [MarshalAs(UnmanagedType.U4)] + public DDSCAPS caps; + [MarshalAs(UnmanagedType.U4)] + public DDSCAPS2 caps2; + public uint caps3; + public uint caps4; + public uint reserved2; + + } + + + public struct DDS_PIXELFORMAT + { + public int size; + [MarshalAs(UnmanagedType.U4)] + public DDPF flags; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public byte[] fourCC; + public uint RGBBitCount; + public uint RBitMask; + public uint GBitMask; + public uint BBitMask; + public uint ABitMask; + } + + + public struct dxt10_header + { + [MarshalAs(UnmanagedType.U4)] + public DDSFormat dxgiFormat; + public uint resourceDimension; + public uint miscFlag; + public uint arraySize; + public uint miscFlags2; + } + + public struct DDS_Info + { + public DDSFormat Format { get; set; } + public DDS_HEADER DDS_HEADER { get; set; } + public dxt10_header dxt10_Header { get; set; } + public byte[] Data { get; set; } + } + + + + public static DDS_Info DdsToTex(byte[] bytes) + { + + MStream memoryList = new MStream(bytes); + + if (memoryList.GetIntValue(false) != 0x20534444) + { + throw new Exception("Invalid dds file"); + } + + DDS_Info dds_info = new DDS_Info(); + dds_info.DDS_HEADER = memoryList.GetStructureValues(); + if (BitConverter.ToInt32(dds_info.DDS_HEADER.ddspf.fourCC, 0) == 0x30315844) + { + dds_info.dxt10_Header = memoryList.GetStructureValues(); + dds_info.Format = dds_info.dxt10_Header.dxgiFormat; + } + dds_info.Data = memoryList.GetBytes((int)(memoryList.GetSize() - memoryList.GetPosition())); + + + if (dds_info.Format == default) + { + + dds_info.Format = GetFormat(dds_info.DDS_HEADER.ddspf); + } +#if false + Console.WriteLine("dxgiFormat: " + dds_info.Format.ToString()); + Console.WriteLine("RGBBitCount: " + dds_info.DDS_HEADER.ddspf.RGBBitCount); + Console.WriteLine("Has Flag: " + dds_info.DDS_HEADER.ddspf.flags.Equals(DDPF.DDPF_RGBA)); + Console.WriteLine("Has RBitMask: " + dds_info.DDS_HEADER.ddspf.RBitMask); + Console.WriteLine("Has GBitMask: " + dds_info.DDS_HEADER.ddspf.GBitMask); + Console.WriteLine("Has BBitMask: " + dds_info.DDS_HEADER.ddspf.BBitMask); + Console.WriteLine("Has ABitMask: " + dds_info.DDS_HEADER.ddspf.ABitMask); + Console.WriteLine("width: " + dds_info.DDS_HEADER.width); + Console.WriteLine("height: " + dds_info.DDS_HEADER.height); + Console.WriteLine("flags: " + dds_info.DDS_HEADER.ddspf.flags.ToString()); + Console.WriteLine("caps: " + dds_info.DDS_HEADER.caps.ToString()); + Console.WriteLine("caps2: " + dds_info.DDS_HEADER.caps2.ToString()); +#endif + return dds_info; + } + + + /// + /// this function is for stream and return DDS_Info.Data + /// + /// + /// + /// + public static DDS_Info DdsToTex(IStream stream) + { + + if (stream.GetIntValue(false) != 0x20534444) + { + throw new Exception("Invalid dds file"); + } + + DDS_Info dds_info = new DDS_Info(); + dds_info.DDS_HEADER = stream.GetStructureValues(); + if (BitConverter.ToInt32(dds_info.DDS_HEADER.ddspf.fourCC, 0) == 0x30315844) + { + dds_info.dxt10_Header = stream.GetStructureValues(); + dds_info.Format = dds_info.dxt10_Header.dxgiFormat; + } + + if (dds_info.Format == default) + { + + dds_info.Format = GetFormat(dds_info.DDS_HEADER.ddspf); + } +#if false + Console.WriteLine("dxgiFormat: " + dds_info.Format.ToString()); + Console.WriteLine("RGBBitCount: " + dds_info.DDS_HEADER.ddspf.RGBBitCount); + Console.WriteLine("Has Flag: " + dds_info.DDS_HEADER.ddspf.flags.Equals(DDPF.DDPF_RGBA)); + Console.WriteLine("Has RBitMask: " + dds_info.DDS_HEADER.ddspf.RBitMask); + Console.WriteLine("Has GBitMask: " + dds_info.DDS_HEADER.ddspf.GBitMask); + Console.WriteLine("Has BBitMask: " + dds_info.DDS_HEADER.ddspf.BBitMask); + Console.WriteLine("Has ABitMask: " + dds_info.DDS_HEADER.ddspf.ABitMask); + Console.WriteLine("width: " + dds_info.DDS_HEADER.width); + Console.WriteLine("height: " + dds_info.DDS_HEADER.height); + Console.WriteLine("flags: " + dds_info.DDS_HEADER.ddspf.flags.ToString()); + Console.WriteLine("caps: " + dds_info.DDS_HEADER.caps.ToString()); + Console.WriteLine("caps2: " + dds_info.DDS_HEADER.caps2.ToString()); +#endif + return dds_info; + } + + + + static bool ISSameMask(DDS_PIXELFORMAT ddspf, uint RBitMask, uint GBitMask, uint BBitMask, uint ABitMask) + { + return ddspf.RBitMask == RBitMask && + ddspf.GBitMask == GBitMask && + ddspf.BBitMask == BBitMask && + ddspf.ABitMask == ABitMask; + } + + + private static DDSFormat GetFormat(DDS_PIXELFORMAT ddspf) + { + + + + if (ddspf.flags > 0 && (ddspf.flags.Equals(DDPF.DDPF_RGB) || ddspf.flags.Equals(DDPF.DDPF_RGBA))) + { + + switch (ddspf.RGBBitCount) + { + + case 32: + { + if (ISSameMask(ddspf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + { + return DDSFormat.r8g8b8a8_unorm; + } + + if (ISSameMask(ddspf, 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000)) + { + return DDSFormat.r10g10b10a2_unorm; + } + + if (ISSameMask(ddspf, 0x0000ffff, 0xffff0000, 0x00000000, 0x00000000)) + { + return DDSFormat.r16g16_unorm; + } + + if (ISSameMask(ddspf, 0xffffffff, 0x00000000, 0x00000000, 0x00000000)) + { + return DDSFormat.r32_float; + } + + if (ISSameMask(ddspf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0)) + { + return DDSFormat.b8g8r8x8_unorm; + } + + if (ISSameMask(ddspf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0)) + { + return DDSFormat.b8g8r8x8_unorm_srgb; + } + + if (ISSameMask(ddspf, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)) + { + + return DDSFormat.b8g8r8a8_unorm; + } + + if (ISSameMask(ddspf, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000)) + { + return DDSFormat.b8g8r8a8_unorm_srgb; + } + break; + } + + case 24: + + if (ISSameMask(ddspf, 0xff0000, 0x00ff00, 0x0000ff, 0)) + { + return DDSFormat.unknown; //R8G8B8 + } + break; + case 16: + { + + + if (ISSameMask(ddspf, 0x7C00, 0x3E0, 0x1F, 0x8000)) + { + return DDSFormat.b5g5r5a1_unorm; + } + + if (ISSameMask(ddspf, 0xf8000000, 0x07e00000, 0x001f0000, 0x00000000)) + { + return DDSFormat.b5g6r5_unorm; + } + + if (ISSameMask(ddspf, 0x0f000000, 0x00f00000, 0x000f0000, 0xf0000000)) + { + return DDSFormat.b4g4r4a4_unorm; + } + + if (ISSameMask(ddspf, 0x00ff, 0, 0, 0xff00)) + { + return DDSFormat.r8g8_uint; + } + break; + } + } + } + else if (ddspf.flags > 0 && (ddspf.flags.Equals(DDPF.DDPF_LUMINANCE) || ddspf.flags.Equals(DDPF.DDPF_LUMINANCEA))) + { + switch (ddspf.RGBBitCount) + { + case 8: + { + if (ISSameMask(ddspf, 0x000000ff, 0x00000000, 0x00000000, 0x00000000)) + { + return DDSFormat.r8_unorm; + } + if (ISSameMask(ddspf, 0xff, 0, 0, 0)) + { + return DDSFormat.r8_uint; + } + break; + } + case 16: + { + if (ISSameMask(ddspf, 0x0000ffff, 0x00000000, 0x00000000, 0x00000000)) + { + return DDSFormat.r16_unorm; + } + + if (ISSameMask(ddspf, 0xFF, 0xFF00, 0x0, 0x0)) + { + return DDSFormat.r8g8_unorm; + } + + if (ISSameMask(ddspf, 0xff, 0x00000000, 0x00000000, 0xFF00)) + { + return DDSFormat.r8g8_unorm; + } + + + if (ISSameMask(ddspf, 0xFF, 0xFF00, 0x0, 0x0)) + { + return DDSFormat.r8g8_unorm; + } + break; + } + + + } + + + } + else if (ddspf.flags > 0 && ddspf.flags.Equals(DDPF.DDPF_ALPHA)) + { + if (ddspf.RGBBitCount == 8) + { + return DDSFormat.a8_unorm; + } + } + + else if (ddspf.flags > 0 && ddspf.flags.Equals(DDPF.DDPF_BUMPDUDV)) + { + + switch (ddspf.RGBBitCount) + { + case 16: + { + if (ISSameMask(ddspf, 0x00ff, 0xff00, 0, 0)) + { + return DDSFormat.r8g8_snorm; + } + + break; + } + } + } + else if (ddspf.flags > 0 && ddspf.flags.Equals(DDPF.DDPF_FOURCC)) + { + switch (Encoding.ASCII.GetString(ddspf.fourCC)) + { + case "DXT1": + return DDSFormat.bc1_unorm; + case "DXT3": + return DDSFormat.bc2_unorm; + case "DXT5": + return DDSFormat.bc3_unorm; + case "BC4U": + return DDSFormat.bc4_unorm; + case "BC4S": + return DDSFormat.bc4_snorm; + case "RGBG": + case "GBGR": + return DDSFormat.r8g8_b8g8_unorm; + case "BC5U": + case "ATI2": + return DDSFormat.r8g8_b8g8_unorm; + case "BC5S": + return DDSFormat.bc5_snorm; + case "YUY2": + return DDSFormat.yuy2; + + } + } + return DDSFormat.unknown; + } + } +} diff --git a/Helper/DDSToBitmap.cs b/Helper/DDSToBitmap.cs new file mode 100644 index 0000000..a4e524d --- /dev/null +++ b/Helper/DDSToBitmap.cs @@ -0,0 +1,623 @@ +using System; +using System.Collections; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; +using System.Runtime.InteropServices.ComTypes; +using static Helper.DDSCooker; + +namespace Helper +{ + public class DDSToBitmap + { + private static DDS_Info info { get; set; } + + //from http://code.google.com/p/kprojects + #region DXT1 + static private Bitmap UncompressDXT1(IStream stream, int w, int h) + { + Bitmap res = new Bitmap((w < 4) ? 4 : w, (h < 4) ? 4 : h); + + for (int j = 0; j < h; j += 4) + { + for (int i = 0; i < w; i += 4) + { + DecompressBlockDXT1(i, j, stream.GetBytes(8), res); + } + } + return res; + } + + static private void DecompressBlockDXT1(int x, int y, byte[] blockStorage, Bitmap image) + { + ushort color0 = (ushort)(blockStorage[0] | blockStorage[1] << 8); + ushort color1 = (ushort)(blockStorage[2] | blockStorage[3] << 8); + + int temp; + + temp = (color0 >> 11) * 255 + 16; + byte r0 = (byte)((temp / 32 + temp) / 32); + temp = ((color0 & 0x07E0) >> 5) * 255 + 32; + byte g0 = (byte)((temp / 64 + temp) / 64); + temp = (color0 & 0x001F) * 255 + 16; + byte b0 = (byte)((temp / 32 + temp) / 32); + + temp = (color1 >> 11) * 255 + 16; + byte r1 = (byte)((temp / 32 + temp) / 32); + temp = ((color1 & 0x07E0) >> 5) * 255 + 32; + byte g1 = (byte)((temp / 64 + temp) / 64); + temp = (color1 & 0x001F) * 255 + 16; + byte b1 = (byte)((temp / 32 + temp) / 32); + + uint code = (uint)(blockStorage[4] | blockStorage[5] << 8 | blockStorage[6] << 16 | blockStorage[7] << 24); + + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + Color finalColor = Color.FromArgb(0); + byte positionCode = (byte)((code >> 2 * (4 * j + i)) & 0x03); + + if (color0 > color1) + { + switch (positionCode) + { + case 0: + finalColor = Color.FromArgb(255, r0, g0, b0); + break; + case 1: + finalColor = Color.FromArgb(255, r1, g1, b1); + break; + case 2: + finalColor = Color.FromArgb(255, (2 * r0 + r1) / 3, (2 * g0 + g1) / 3, (2 * b0 + b1) / 3); + break; + case 3: + finalColor = Color.FromArgb(255, (r0 + 2 * r1) / 3, (g0 + 2 * g1) / 3, (b0 + 2 * b1) / 3); + break; + } + } + else + { + switch (positionCode) + { + case 0: + finalColor = Color.FromArgb(255, r0, g0, b0); + break; + case 1: + finalColor = Color.FromArgb(255, r1, g1, b1); + break; + case 2: + finalColor = Color.FromArgb(255, (r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2); + break; + case 3: + finalColor = Color.FromArgb(255, 0, 0, 0); + break; + } + } + + image.SetPixel(x + i, y + j, finalColor); + } + } + } + #endregion + //from http://code.google.com/p/kprojects + #region DXT5 + static private Bitmap UncompressDXT5(IStream stream, int w, int h) + { + Bitmap res = new Bitmap((w < 4) ? 4 : w, (h < 4) ? 4 : h); + + for (int j = 0; j < h; j += 4) + { + for (int i = 0; i < w; i += 4) + { + DecompressBlockDXT5(i, j, stream.GetBytes(16), res); + } + } + return res; + } + + static void DecompressBlockDXT5(int x, int y, byte[] blockStorage, Bitmap image) + { + byte alpha0 = blockStorage[0]; + byte alpha1 = blockStorage[1]; + + int bitOffset = 2; + uint alphaCode1 = (uint)(blockStorage[bitOffset + 2] | (blockStorage[bitOffset + 3] << 8) | (blockStorage[bitOffset + 4] << 16) | (blockStorage[bitOffset + 5] << 24)); + ushort alphaCode2 = (ushort)(blockStorage[bitOffset + 0] | (blockStorage[bitOffset + 1] << 8)); + + ushort color0 = (ushort)(blockStorage[8] | blockStorage[9] << 8); + ushort color1 = (ushort)(blockStorage[10] | blockStorage[11] << 8); + + int temp; + + temp = (color0 >> 11) * 255 + 16; + byte r0 = (byte)((temp / 32 + temp) / 32); + temp = ((color0 & 0x07E0) >> 5) * 255 + 32; + byte g0 = (byte)((temp / 64 + temp) / 64); + temp = (color0 & 0x001F) * 255 + 16; + byte b0 = (byte)((temp / 32 + temp) / 32); + + temp = (color1 >> 11) * 255 + 16; + byte r1 = (byte)((temp / 32 + temp) / 32); + temp = ((color1 & 0x07E0) >> 5) * 255 + 32; + byte g1 = (byte)((temp / 64 + temp) / 64); + temp = (color1 & 0x001F) * 255 + 16; + byte b1 = (byte)((temp / 32 + temp) / 32); + + uint code = (uint)(blockStorage[12] | blockStorage[13] << 8 | blockStorage[14] << 16 | blockStorage[15] << 24); + + for (int j = 0; j < 4; j++) + { + for (int i = 0; i < 4; i++) + { + int alphaCodeIndex = 3 * (4 * j + i); + int alphaCode; + + if (alphaCodeIndex <= 12) + { + alphaCode = (alphaCode2 >> alphaCodeIndex) & 0x07; + } + else if (alphaCodeIndex == 15) + { + alphaCode = (int)((alphaCode2 >> 15) | ((alphaCode1 << 1) & 0x06)); + } + else + { + alphaCode = (int)((alphaCode1 >> (alphaCodeIndex - 16)) & 0x07); + } + + byte finalAlpha; + if (alphaCode == 0) + { + finalAlpha = alpha0; + } + else if (alphaCode == 1) + { + finalAlpha = alpha1; + } + else + { + if (alpha0 > alpha1) + { + finalAlpha = (byte)(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7); + } + else + { + if (alphaCode == 6) + finalAlpha = 0; + else if (alphaCode == 7) + finalAlpha = 255; + else + finalAlpha = (byte)(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5); + } + } + + byte colorCode = (byte)((code >> 2 * (4 * j + i)) & 0x03); + + Color finalColor = new Color(); + switch (colorCode) + { + case 0: + finalColor = Color.FromArgb(finalAlpha, r0, g0, b0); + break; + case 1: + finalColor = Color.FromArgb(finalAlpha, r1, g1, b1); + break; + case 2: + finalColor = Color.FromArgb(finalAlpha, (2 * r0 + r1) / 3, (2 * g0 + g1) / 3, (2 * b0 + b1) / 3); + break; + case 3: + finalColor = Color.FromArgb(finalAlpha, (r0 + 2 * r1) / 3, (g0 + 2 * g1) / 3, (b0 + 2 * b1) / 3); + break; + } + image.SetPixel(x + i, y + j, finalColor); + } + } + } + #endregion + //from https://github.com/ME3Tweaks/ME3ExplorerLib/blob/c9144346af32d9cab674f2cd0ad1bcb3358ed34f/Helpers/DDSImage.cs + #region DXT3 + private static Bitmap UncompressDXT3(IStream stream, int w, int h) + { + const int bufferSize = 16; + byte[] blockStorage = new byte[bufferSize]; + using (MemoryStream bitmapStream = new MemoryStream(w * h * 2)) + { + using (BinaryWriter bitmapBW = new BinaryWriter(bitmapStream)) + { + int ptr = 0; + for (int s = 0; s < h; s += 4) + { + for (int t = 0; t < w; t += 4) + { + blockStorage=stream.GetBytes(bufferSize, false, ptr); + ptr += bufferSize; + { + int color0 = blockStorage[8] | blockStorage[9] << 8; + int color1 = blockStorage[10] | blockStorage[11] << 8; + + int temp; + + temp = (color0 >> 11) * 255 + 16; + int r0 = ((temp >> 5) + temp) >> 5; + temp = ((color0 & 0x07E0) >> 5) * 255 + 32; + int g0 = ((temp >> 6) + temp) >> 6; + temp = (color0 & 0x001F) * 255 + 16; + int b0 = ((temp >> 5) + temp) >> 5; + + temp = (color1 >> 11) * 255 + 16; + int r1 = ((temp >> 5) + temp) >> 5; + temp = ((color1 & 0x07E0) >> 5) * 255 + 32; + int g1 = ((temp >> 6) + temp) >> 6; + temp = (color1 & 0x001F) * 255 + 16; + int b1 = ((temp >> 5) + temp) >> 5; + + int code = blockStorage[12] | blockStorage[13] << 8 | blockStorage[14] << 16 | blockStorage[15] << 24; + + for (int j = 0; j < 4; j++) + { + bitmapStream.Seek(((s + j) * w * 4) + (t * 4), SeekOrigin.Begin); + for (int i = 0; i < 4; i++) + { + byte alpha = (byte)((blockStorage[(j * i) < 8 ? 0 : 1] >> (((i * j) % 8) * 4)) & 0xFF); + alpha = (byte)((alpha << 4) | alpha); + if (!IsAlpha()) + alpha = 0xFF; + + int fCol = 0; + int colorCode = (code >> 2 * (4 * j + i)) & 0x03; + + switch (colorCode) + { + case 0: + fCol = b0 | g0 << 8 | r0 << 16 | 0xFF << alpha; + break; + case 1: + fCol = b1 | g1 << 8 | r1 << 16 | 0xFF << alpha; + break; + case 2: + fCol = (2 * b0 + b1) / 3 | (2 * g0 + g1) / 3 << 8 | (2 * r0 + r1) / 3 << 16 | 0xFF << alpha; + break; + case 3: + fCol = (b0 + 2 * b1) / 3 | (g0 + 2 * g1) / 3 << 8 | (r0 + 2 * r1) / 3 << 16 | 0xFF << alpha; + break; + } + + bitmapBW.Write(fCol); + } + } + } + } + } + + + var bmp = new Bitmap(w, h, System.Drawing.Imaging.PixelFormat.Format32bppArgb); + { + BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, + bmp.Width, + bmp.Height), + ImageLockMode.WriteOnly, + bmp.PixelFormat); + + Marshal.Copy(bitmapStream.ToArray(), 0, bmpData.Scan0, (int)bitmapStream.Length); + bmp.UnlockBits(bmpData); + } + + return bmp; + } + } + } + #endregion + + #region A8R8G8B8 or X8R8G8B8 or A8B8G8R8 or X8B8G8R8 + static private Bitmap Uncompress8_8_8_8(IStream stream, int w, int h) + { + uint RBitMask = info.DDS_HEADER.ddspf.RBitMask; + uint GBitMask = info.DDS_HEADER.ddspf.GBitMask; + uint BBitMask = info.DDS_HEADER.ddspf.BBitMask; + uint ABitMask = info.DDS_HEADER.ddspf.ABitMask; + + + if (info.DDS_HEADER.ddspf.RGBBitCount == 0) + { + (RBitMask, GBitMask, BBitMask, ABitMask) = DDSCooker.GetMask(info.Format); + } + + Bitmap bitmap = new Bitmap(w, h); + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetUIntValue(); + int b = GetMaskValue(BBitMask, RGBABits); + int g = GetMaskValue(GBitMask, RGBABits); + int r = GetMaskValue(RBitMask, RGBABits); + int a = GetMaskValue(ABitMask, RGBABits); + if (!IsAlpha()) + { + a = 255; + } + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + #region A8L8 + static private Bitmap UncompressA8L8(IStream stream, int w, int h) + { + Bitmap bitmap = new Bitmap(w, h); + + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetUShortValue(); + int b = GetMaskValue(info.DDS_HEADER.ddspf.BBitMask, RGBABits); + int g = GetMaskValue(info.DDS_HEADER.ddspf.GBitMask, RGBABits); + int r = GetMaskValue(info.DDS_HEADER.ddspf.RBitMask, RGBABits); + int a = GetMaskValue(info.DDS_HEADER.ddspf.ABitMask, RGBABits); + if (!IsAlpha()) + { + a = 255; + } + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + #region V8U8 + static private Bitmap UncompressV8U8(IStream stream, int w, int h) + { + Bitmap bitmap = new Bitmap(w, h); + int Step = 0; + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetUShortValue(); + int r = 0x7F + (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.RBitMask, RGBABits); + int g = 0x7F + (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.GBitMask, RGBABits); + int b = 0xff; + int a = 0xff; + + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + #region B4G4R4A4 + static private Bitmap UncompressB4G4R4A4(IStream stream, int w, int h) + { + Bitmap bitmap = new Bitmap(w, h); + int Step = 0; + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetUShortValue(); + int r = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.RBitMask, RGBABits) << 4; + int g = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.GBitMask, RGBABits) << 4; + int b = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.BBitMask, RGBABits) << 4; + int a = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.ABitMask, RGBABits) << 4; + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + #region B5G5R5A1 + static private Bitmap UncompressB5G5R5A1(IStream stream, int w, int h) + { + Bitmap bitmap = new Bitmap(w, h); + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetUShortValue(); + int r = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.RBitMask, RGBABits) << 3; + int g = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.GBitMask, RGBABits) << 3; + int b = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.BBitMask, RGBABits) << 3; + int a = (sbyte)GetMaskValue(info.DDS_HEADER.ddspf.ABitMask, RGBABits) == 1 ? 255 : 0; + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + #region L8 or A8 + static private Bitmap Uncompress8bits(IStream stream, int w, int h) + { + Bitmap bitmap = new Bitmap(w, h); + for (int y = 0; y < bitmap.Height; y++) + { + for (int x = 0; x < bitmap.Width; x++) + { + uint RGBABits = stream.GetByteValue(); + int r = 0xff; + int g = 0xff; + int b = 0xff; + int a = 0xff; + if (info.Format == DDSFormat.r8_unorm) + { + r = (int)RGBABits; + g = (int)RGBABits; + b = (int)RGBABits; + a = 0xff; + } + if (info.Format == DDSFormat.a8_unorm) + { + r = 0xff; + g = 0xff; + b = 0xff; + a = (int)RGBABits; + } + + bitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); + } + + } + return bitmap; + } + #endregion + + private static bool IsAlpha() + { + if (info.DDS_HEADER.ddspf.flags.Equals(DDPF.DDPF_PAL8A) + || info.DDS_HEADER.ddspf.flags.Equals(DDPF.DDPF_ALPHA) + || info.DDS_HEADER.ddspf.flags.Equals(DDPF.DDPF_RGBA)) + { + return true; + } + + return false; + } + + private static byte GetMaskValue(uint Mask, uint Bits) + { + + BitArray Valuebits = new BitArray(BitConverter.GetBytes(Bits & Mask)); + BitArray Maskbits = new BitArray(BitConverter.GetBytes(Mask)); + int t = 0; + for (int n = 0; n < Maskbits.Length; n++) + { + if (Maskbits[n] == true) + { + bool value = Valuebits[n]; + Valuebits[n] = false; + Valuebits[t++] = value; + } + + } + + byte[] bytes = new byte[(Valuebits.Length / 8) + 1]; + Valuebits.CopyTo(bytes, 0); + + return bytes[0]; + } + + public static Bitmap Convert(byte[] DDSBytes) + { + + info = DDSCooker.DdsToTex(DDSBytes); + + var stream = new MStream(info.Data); + + return GetBitMapFromDDS(info.Format, stream); + } + + + public static Bitmap Convert(IStream stream) + { + info= DDSCooker.DdsToTex(stream); + return GetBitMapFromDDS(info.Format, stream); + } + + + + public static Bitmap Convert(byte[] DDSBytes, DDSFormat format, int w, int h) + { + DDPF dwFlags = 0; + if (format == DDSFormat.bc1_unorm || format == DDSFormat.bc2_unorm || format == DDSFormat.bc3_unorm) + { + dwFlags = DDPF.DDPF_FOURCC; + } + else if (format == DDSFormat.r8_unorm || format == DDSFormat.r16_unorm || format == DDSFormat.r8g8_unorm) + { + dwFlags = DDPF.DDPF_LUMINANCE; + } + else if (format == DDSFormat.a8_unorm) + { + dwFlags = DDPF.DDPF_ALPHA; + } + else + { + dwFlags = DDPF.DDPF_ALPHAPIXELS | DDPF.DDPF_RGB; + } + (uint RBitMask, uint GBitMask, uint BBitMask, uint ABitMask) = DDSCooker.GetMask(format); + info = new DDS_Info() + { + DDS_HEADER = new DDS_HEADER() + { + width = w, + height = h, + ddspf = new DDS_PIXELFORMAT() + { + flags = dwFlags, + RGBBitCount = BitsPerPixel(format), + RBitMask = RBitMask, + GBitMask = GBitMask, + BBitMask = BBitMask, + ABitMask = ABitMask + } + }, + Format = format, + Data = DDSBytes + }; + + var stream = new MStream(info.Data); + return GetBitMapFromDDS(format, stream); + + } + + private static Bitmap GetBitMapFromDDS(DDSFormat format, IStream stream) + { + switch (format) + { + case DDSFormat.bc1_unorm: + case DDSFormat.bc1_unorm_srgb: + return UncompressDXT1(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.bc2_unorm: + case DDSFormat.bc2_unorm_srgb: + return UncompressDXT3(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.bc3_unorm: + case DDSFormat.bc3_unorm_srgb: + return UncompressDXT5(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.b8g8r8a8_unorm: + case DDSFormat.b8g8r8x8_unorm: + case DDSFormat.b8g8r8a8_unorm_srgb: + case DDSFormat.b8g8r8x8_unorm_srgb: + case DDSFormat.r8g8b8a8_unorm: + case DDSFormat.r8g8b8a8_unorm_srgb: + return Uncompress8_8_8_8(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.r8g8_unorm: + return UncompressA8L8(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.r8g8_snorm: + return UncompressV8U8(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.r8_unorm: + case DDSFormat.a8_unorm: + return Uncompress8bits(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.b4g4r4a4_unorm: + return UncompressB4G4R4A4(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + case DDSFormat.b5g5r5a1_unorm: + return UncompressB5G5R5A1(stream, info.DDS_HEADER.width, info.DDS_HEADER.height); + + default: + throw new Exception("Unsupported DDS Format"); + + + } + } + } +} diff --git a/alan wake 2 rmdtoc tool.csproj b/alan wake 2 rmdtoc tool.csproj index 06fb869..abac08f 100644 --- a/alan wake 2 rmdtoc tool.csproj +++ b/alan wake 2 rmdtoc tool.csproj @@ -17,7 +17,7 @@ AnyCPU true full - true + false bin\Debug\ DEBUG;TRACE prompt @@ -76,9 +76,21 @@ Component + + UserControl + + + SearchBox.cs + + + Form + + + frmImageViewer.cs + Form @@ -91,12 +103,20 @@ FrmStringTable.cs + + + + SearchBox.cs + + + frmImageViewer.cs + FrmMain.cs