From 4ce56fe682b458af160af6ace18ebef94f651a03 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 23 Mar 2024 11:15:20 +0100 Subject: [PATCH 1/9] MainForm - Only set file icons and click event if file is supported --- PCK-Studio/MainForm.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 58a0f287..54c4efee 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -99,7 +99,7 @@ namespace PckStudio [PckFileType.ColourTableFile] = HandleColourFile, [PckFileType.GameRulesHeader] = HandleGameRuleFile, [PckFileType.SkinDataFile] = HandleInnerPckFile, - [PckFileType.ModelsFile] = HandleModelsFile, + [PckFileType.ModelsFile] = null, //HandleModelsFile, // Note: Uncomment when implemented [PckFileType.BehavioursFile] = HandleBehavioursFile, [PckFileType.MaterialFile] = HandleMaterialFile, }; @@ -107,6 +107,8 @@ namespace PckStudio private void HandleInnerPckFile(PckFileData file) { + // TODO: decide on how to handle embedded pck files + return; if (Settings.Default.LoadSubPcks && (file.Filetype == PckFileType.SkinDataFile || file.Filetype == PckFileType.TexturePackInfoFile) && file.Size > 0 && treeViewMain.SelectedNode.Nodes.Count == 0) @@ -1878,6 +1880,7 @@ namespace PckStudio node.SelectedImageIndex = 3; break; case PckFileType.TexturePackInfoFile: + goto default; node.ImageIndex = 4; node.SelectedImageIndex = 4; break; @@ -1886,10 +1889,12 @@ namespace PckStudio node.SelectedImageIndex = 6; break; case PckFileType.ModelsFile: + goto default; node.ImageIndex = 8; node.SelectedImageIndex = 8; break; case PckFileType.SkinDataFile: + goto default; node.ImageIndex = 7; node.SelectedImageIndex = 7; break; From 123d529270f72007ddc4603efe2a6c9eb3a8f72d Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 23 Mar 2024 16:17:07 +0100 Subject: [PATCH 2/9] MainForm - Fix deleting folder being flaged as having compass or clock textures inside --- PCK-Studio/MainForm.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 54c4efee..2b1e36a4 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -837,7 +837,7 @@ namespace PckStudio MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) { string pckFolderDir = node.FullPath; - currentPCK.RemoveAll(file => !BeforeFileRemove(file) && file.Filename.StartsWith(pckFolderDir)); + currentPCK.RemoveAll(file => file.Filename.StartsWith(pckFolderDir) && !BeforeFileRemove(file)); node.Remove(); wasModified = true; } From e980aeeae9b1b6bc15cd118e8631cd40efba8656 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 23 Mar 2024 18:15:30 +0100 Subject: [PATCH 3/9] MainForm - Fix checking for audio file instead of a specific name --- PCK-Studio/MainForm.cs | 4 ++-- Vendor/OMI-Lib | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 2b1e36a4..1de0c877 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -944,10 +944,10 @@ namespace PckStudio private void audiopckToolStripMenuItem_Click(object sender, EventArgs e) { - if (currentPCK.Contains("audio.pck", PckFileType.AudioFile)) + if (currentPCK.Contains(PckFileType.AudioFile)) { // the chance of this happening is really really slim but just in case - MessageBox.Show("There is already a file in this PCK named \"audio.pck\"!", "Can't create audio.pck"); + MessageBox.Show("There is already an audio file in this PCK!", "Can't create audio.pck"); return; } if (string.IsNullOrEmpty(saveLocation)) diff --git a/Vendor/OMI-Lib b/Vendor/OMI-Lib index 40795ea8..9ec8c222 160000 --- a/Vendor/OMI-Lib +++ b/Vendor/OMI-Lib @@ -1 +1 @@ -Subproject commit 40795ea8a58eb1bd4933f1cf50315d5aea4909ef +Subproject commit 9ec8c2228bbbda2c415f91d284d391a2a9152a3d From 20a97bafb4f36512cf1663b45f5575175858be3c Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 23 Mar 2024 18:21:53 +0100 Subject: [PATCH 4/9] MainForm - Fix clone function working on folders --- PCK-Studio/MainForm.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 1de0c877..7b2ebeac 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -1170,7 +1170,8 @@ namespace PckStudio private void cloneFileToolStripMenuItem_Click(object sender, EventArgs e) { TreeNode node = treeViewMain.SelectedNode; - if (node == null) return; + if (node == null || !node.IsTagOfType()) + return; string path = node.FullPath; using TextPrompt diag = new TextPrompt(node.Tag is null ? Path.GetFileName(node.FullPath) : node.FullPath); From 3cb6097d14d1fca836398db2dc3bebbbeb4b997c Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sat, 23 Mar 2024 18:32:46 +0100 Subject: [PATCH 5/9] MainForm - Fix importing file that already exists --- PCK-Studio/MainForm.cs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 7b2ebeac..d8fb5d75 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -1949,6 +1949,7 @@ namespace PckStudio } } + [Obsolete()] private void addTextureToolStripMenuItem_Click(object sender, EventArgs e) { using OpenFileDialog fileDialog = new OpenFileDialog(); @@ -1959,8 +1960,12 @@ namespace PckStudio renamePrompt.LabelText = "Path"; if (renamePrompt.ShowDialog() == DialogResult.OK && !string.IsNullOrEmpty(renamePrompt.NewText)) { - var file = currentPCK.CreateNewFile(renamePrompt.NewText, PckFileType.TextureFile); - file.SetData(File.ReadAllBytes(fileDialog.FileName)); + if (currentPCK.Contains(renamePrompt.NewText, PckFileType.TextureFile)) + { + MessageBox.Show($"'{renamePrompt.NewText}' already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + var file = currentPCK.CreateNewFile(renamePrompt.NewText, PckFileType.TextureFile, () => File.ReadAllBytes(fileDialog.FileName)); BuildMainTreeView(); wasModified = true; } @@ -2160,7 +2165,8 @@ namespace PckStudio private void addFileToolStripMenuItem_Click(object sender, EventArgs e) { using var ofd = new OpenFileDialog(); - // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? So now it's formatted correctly and now displays the file type name in the dialog. + // Suddenly, and randomly, this started throwing an exception because it wasn't formatted correctly? + // So now it's formatted correctly and now displays the file type name in the dialog. ofd.Filter = "All files (*.*)|*.*"; ofd.Multiselect = false; @@ -2169,13 +2175,14 @@ namespace PckStudio using AddFilePrompt diag = new AddFilePrompt("res/" + Path.GetFileName(ofd.FileName)); if (diag.ShowDialog(this) == DialogResult.OK) { - PckFileData file = currentPCK.CreateNewFile( - diag.Filepath, - diag.Filetype, - () => File.ReadAllBytes(ofd.FileName)); + if (currentPCK.Contains(diag.Filepath, diag.Filetype)) + { + MessageBox.Show($"'{diag.Filepath}' of type {diag.Filetype} already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + PckFileData file = currentPCK.CreateNewFile(diag.Filepath, diag.Filetype, () => File.ReadAllBytes(ofd.FileName)); RebuildSubPCK(treeViewMain.SelectedNode.FullPath); - //else treeViewMain.Nodes.Add(); BuildMainTreeView(); wasModified = true; From f645914ee6c29dc74f38b1a0548439363eb609f7 Mon Sep 17 00:00:00 2001 From: Miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 24 Mar 2024 14:48:49 +0100 Subject: [PATCH 6/9] Add Tga file support (#25) * Add minimal tga image loader * Update TGA class ,add support for importing tga texture files and generate mipmap from tga images * Add copyright and resource links * Partial Add SaveImage * Move TGAReader/Writer outside of TGA.cs * Add check to return early when `DataTypeCode` is set to NO_DATA * Add support for loading ExtensionData * Change PNG signature check more clear * Remove unnecessary using statements * Move Debug stuff into Debug methods and call LoadImage before LoadFooter * Update TGAReader * Update TGA Reader/Writer * Remove TGATimeSpan and use TimeSpan and DateTime instead * Update TGAHeader member varible name and type * Update TGA- Reader/Writer Constructor to not accept boolean flag 'useLittleEndian' * TGAReader - Optimized 'TGA_HandleRGB' * TGAReader - Update and rename 'TGA_HandleRLE_RGB' * TGAWriter - Remove RLE RGB from switch statement * TGA - Add TGA.FromFile, Move TGADataTypeCode to its own file * Move Header, Footer and ExtentionData to there own cs file * Move Tga files into IO folder * Changed visibility of tga related classes to internal * TGA - Only support reading/writting of raw RGB 32 bit images * Update IO/TGA classes --- PCK-Studio/Classes/IO/TGA/TGADataTypeCode.cs | 60 +++++ PCK-Studio/Classes/IO/TGA/TGADeserializer.cs | 33 +++ PCK-Studio/Classes/IO/TGA/TGAException.cs | 25 ++ PCK-Studio/Classes/IO/TGA/TGAExtentionData.cs | 63 +++++ PCK-Studio/Classes/IO/TGA/TGAFileData.cs | 41 +++ PCK-Studio/Classes/IO/TGA/TGAFooter.cs | 27 ++ PCK-Studio/Classes/IO/TGA/TGAHeader.cs | 37 +++ PCK-Studio/Classes/IO/TGA/TGAReader.cs | 241 ++++++++++++++++++ PCK-Studio/Classes/IO/TGA/TGASerializer.cs | 32 +++ PCK-Studio/Classes/IO/TGA/TGAWriter.cs | 143 +++++++++++ .../Extensions/PckFileDataExtensions.cs | 6 +- PCK-Studio/MainForm.cs | 14 +- PCK-Studio/PckStudio.csproj | 12 +- 13 files changed, 721 insertions(+), 13 deletions(-) create mode 100644 PCK-Studio/Classes/IO/TGA/TGADataTypeCode.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGADeserializer.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAException.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAExtentionData.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAFileData.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAFooter.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAHeader.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAReader.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGASerializer.cs create mode 100644 PCK-Studio/Classes/IO/TGA/TGAWriter.cs diff --git a/PCK-Studio/Classes/IO/TGA/TGADataTypeCode.cs b/PCK-Studio/Classes/IO/TGA/TGADataTypeCode.cs new file mode 100644 index 00000000..60456312 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGADataTypeCode.cs @@ -0,0 +1,60 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ + +namespace PckStudio.IO.TGA +{ + internal enum TGADataTypeCode : byte + { + /// + /// No image data included. + /// + NO_DATA = 0, + /// + /// Uncompressed, color-mapped images. + /// + COLORMAPPED = 1, + /// + /// Uncompressed, RGB images. + /// + RGB = 2, + /// + /// Uncompressed, black and white images. + /// + BLACK_WHITE = 3, + /// + /// Runlength encoded color-mapped images. + /// + RLE_COLORMAPPED = 9, + /// + /// Runlength encoded RGB images. + /// + RLE_RGB = 10, + /// + /// Compressed, black and white images. + /// + COMPRESSED_BLACK_WHITE = 11, + /// + /// Compressed color-mapped data, using Huffman, Delta, and runlength encoding. + /// + COMPRESSED_RLE_COLORMAPPED = 32, + /// + /// Compressed color-mapped data, using Huffman, Delta, and runlength encoding. 4-pass quadtree-type process. + /// + COMPRESSED_RLE_COLORMAPPED_4 = 33, + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGADeserializer.cs b/PCK-Studio/Classes/IO/TGA/TGADeserializer.cs new file mode 100644 index 00000000..0382e16e --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGADeserializer.cs @@ -0,0 +1,33 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System.IO; +using System.Drawing; + +namespace PckStudio.IO.TGA +{ + internal static class TGADeserializer + { + private static TGAReader reader = new TGAReader(); + + public static Image DeserializeFromStream(Stream stream) + { + TGAFileData tgaImg = reader.FromStream(stream); + return tgaImg.Bitmap; + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAException.cs b/PCK-Studio/Classes/IO/TGA/TGAException.cs new file mode 100644 index 00000000..9f961579 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAException.cs @@ -0,0 +1,25 @@ +using System; +using System.Runtime.Serialization; + +namespace PckStudio.IO.TGA +{ + [Serializable] + internal class TGAException : Exception + { + public TGAException() + { + } + + public TGAException(string message) : base(message) + { + } + + public TGAException(string message, Exception innerException) : base(message, innerException) + { + } + + protected TGAException(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAExtentionData.cs b/PCK-Studio/Classes/IO/TGA/TGAExtentionData.cs new file mode 100644 index 00000000..55485144 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAExtentionData.cs @@ -0,0 +1,63 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System; +using System.Windows.Forms; + +namespace PckStudio.IO.TGA +{ + internal struct TGAExtentionData + { + public const short ExtensionSize = 0x1EF; + public string AuthorName; + public string AuthorComment; + public DateTime TimeStamp; + public string JobID; + public TimeSpan JobTime; + public string SoftwareID; + public byte[] SoftwareVersion; + public int KeyColor; + public int PixelAspectRatio; + public int GammaValue; + public int ColorCorrectionOffset; + public int PostageStampOffset; + public int ScanLineOffset; + public byte AttributesType; + + public static TGAExtentionData Create() + { + var extensionData = new TGAExtentionData(); + extensionData.AuthorName = ""; + extensionData.AuthorComment = ""; + extensionData.AuthorComment = ""; + extensionData.TimeStamp = DateTime.Now; + extensionData.JobID = ""; + extensionData.JobTime = new TimeSpan(extensionData.TimeStamp.Hour, extensionData.TimeStamp.Minute, extensionData.TimeStamp.Second); + extensionData.SoftwareID = Application.ProductName; + Version.TryParse(Application.ProductVersion, out Version currentVersion); + extensionData.SoftwareVersion = [(byte)currentVersion.Major, (byte)currentVersion.Minor, (byte)currentVersion.Build]; + extensionData.KeyColor = 0; + extensionData.PixelAspectRatio = 0; + extensionData.GammaValue = 0; + extensionData.ColorCorrectionOffset = 0; + extensionData.PostageStampOffset = 0; + extensionData.ScanLineOffset = 0; + extensionData.AttributesType = 3; + return extensionData; + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAFileData.cs b/PCK-Studio/Classes/IO/TGA/TGAFileData.cs new file mode 100644 index 00000000..f4a12859 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAFileData.cs @@ -0,0 +1,41 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System.IO; +using System.Drawing; +using System; + +namespace PckStudio.IO.TGA +{ + internal class TGAFileData + { + public TGAFileData(TGAHeader header, Image bitmap, TGAFooter footer, TGAExtentionData extentionData) + { + if (bitmap.Width != header.Width || bitmap.Height != header.Height) + throw new InvalidDataException("Header resolution doesn't match Image resolution"); + Header = header; + Bitmap = bitmap; + Footer = footer; + ExtentionData = extentionData; + } + + public readonly TGAHeader Header; + public readonly Image Bitmap; + public readonly TGAFooter Footer; + public readonly TGAExtentionData ExtentionData; + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAFooter.cs b/PCK-Studio/Classes/IO/TGA/TGAFooter.cs new file mode 100644 index 00000000..cfae98c8 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAFooter.cs @@ -0,0 +1,27 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ + +namespace PckStudio.IO.TGA +{ + internal struct TGAFooter + { + internal const string Signature = "TRUEVISION-XFILE"; + public int ExtensionDataOffset; + public int DeveloperAreaDataOffset; + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAHeader.cs b/PCK-Studio/Classes/IO/TGA/TGAHeader.cs new file mode 100644 index 00000000..ce967b22 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAHeader.cs @@ -0,0 +1,37 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ + +namespace PckStudio.IO.TGA +{ + /// + /// Resources: + /// + /// + /// + internal struct TGAHeader + { + public byte[] Id; + public TGADataTypeCode DataTypeCode; + public (byte Type, short Origin/*Offset*/, short Length, byte Depth) Colormap; + public (short X, short Y) Origin; + public short Width; + public short Height; + public byte BitsPerPixel; + public byte ImageDescriptor; + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAReader.cs b/PCK-Studio/Classes/IO/TGA/TGAReader.cs new file mode 100644 index 00000000..112d2fc7 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAReader.cs @@ -0,0 +1,241 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System; +using System.IO; +using System.Text; +using System.Drawing; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.Collections.Generic; +using OMI.Workers; +using OMI; + +namespace PckStudio.IO.TGA +{ + internal class TGAReader : IDataFormatReader, IDataFormatReader + { + object IDataFormatReader.FromStream(Stream stream) => FromStream(stream); + + object IDataFormatReader.FromFile(string filename) => FromFile(filename); + + public TGAFileData FromFile(string filename) + { + if (File.Exists(filename)) + { + using( var fs = File.OpenRead(filename) ) + { + return FromStream(fs); + } + } + throw new FileNotFoundException(filename); + } + + public TGAFileData FromStream(Stream stream) + { + using var reader = new EndiannessAwareBinaryReader(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian); + TGAHeader header = LoadHeader(reader); + Image image = LoadImage(reader, header); + TGAFooter footer = LoadFooter(reader); + TGAExtentionData extentionData = LoadExtentionData(reader, footer); + return new TGAFileData(header, image, footer, extentionData); + } + + private static void TGA_HandleRGB(EndiannessAwareBinaryReader reader, TGAHeader header, BitmapData bitmapData) + { + int bytesPerPixel = header.BitsPerPixel / 8; + + byte[] data = reader.ReadBytes(header.Height * header.Width * bytesPerPixel); + Marshal.Copy(data, 0, bitmapData.Scan0, data.Length); + } + + private static void TGA_HandleNoData(EndiannessAwareBinaryReader _, TGAHeader header, BitmapData bitmapData) + { + Random r = new Random(); + byte[] bytes = new byte[bitmapData.Width * bitmapData.Height * 4]; + r.NextBytes(bytes); + Marshal.Copy(bytes, 0, bitmapData.Scan0, bytes.Length); + } + + private static TGAHeader LoadHeader(EndiannessAwareBinaryReader reader) + { + var header = new TGAHeader(); + byte[] bytes = reader.ReadBytes(3); + (var headerIdLength, header.Colormap.Type, header.DataTypeCode) = (bytes[0], bytes[1], (TGADataTypeCode)bytes[2]); + header.Colormap.Origin = reader.ReadInt16(); + header.Colormap.Length = reader.ReadInt16(); + header.Colormap.Depth = reader.ReadByte(); + header.Origin.X = reader.ReadInt16(); + header.Origin.Y = reader.ReadInt16(); + header.Width = reader.ReadInt16(); + header.Height = reader.ReadInt16(); + header.BitsPerPixel = reader.ReadByte(); + header.ImageDescriptor = reader.ReadByte(); + header.Id = reader.ReadBytes(headerIdLength); + DebugLogHeader(header); + return header; + } + + private static PixelFormat GetPixelFormat(int bytesPerPixel) + { + return bytesPerPixel switch + { + 2 => PixelFormat.Format16bppArgb1555, + 3 => PixelFormat.Format24bppRgb, + 4 => PixelFormat.Format32bppArgb, + _ => throw new NotSupportedException(nameof(bytesPerPixel)) + }; + } + + private static Image LoadImage(EndiannessAwareBinaryReader reader, TGAHeader header) + { + if (header.DataTypeCode != TGADataTypeCode.RGB) + throw new NotSupportedException(nameof(header.DataTypeCode)); + + Bitmap bitmap = new Bitmap(header.Width, header.Height); + BitmapData bitmapData = bitmap.LockBits( + new Rectangle(0, 0, header.Width, header.Height), + ImageLockMode.WriteOnly, + GetPixelFormat(header.BitsPerPixel >> 3)); + + if (header.DataTypeCode == TGADataTypeCode.NO_DATA) + { + TGA_HandleNoData(reader, header, bitmapData); + bitmap.UnlockBits(bitmapData); + return bitmap; + } + + TGA_HandleRGB(reader, header, bitmapData); + bitmap.UnlockBits(bitmapData); + bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); + return bitmap; + } + + private static TGAFooter LoadFooter(EndiannessAwareBinaryReader reader) + { + long origin = reader.BaseStream.Position; + reader.BaseStream.Seek(-26, SeekOrigin.End); + + TGAFooter footer = new TGAFooter(); + + footer.ExtensionDataOffset = reader.ReadInt32(); // optional + footer.DeveloperAreaDataOffset = reader.ReadInt32(); // optional + string signature = reader.ReadString(16); + Debug.Assert(signature.Equals(TGAFooter.Signature) || reader.ReadInt16() != 0x002E, + "Footer signature invalid"); + reader.BaseStream.Seek(origin, SeekOrigin.Begin); + DebugLogFooter(footer); + return footer; + } + + private static TGAExtentionData LoadExtentionData(EndiannessAwareBinaryReader reader, TGAFooter footer) + { + if (footer.ExtensionDataOffset > 0) + { + reader.BaseStream.Seek(footer.ExtensionDataOffset, SeekOrigin.Begin); + if (reader.ReadInt16() == TGAExtentionData.ExtensionSize) + { + TGAExtentionData extentionData = new TGAExtentionData(); + extentionData.AuthorName = reader.ReadString(41); + extentionData.AuthorComment = reader.ReadString(324); + short month = reader.ReadInt16(); + short day = reader.ReadInt16(); + short year = reader.ReadInt16(); + short hour = reader.ReadInt16(); + short minute = reader.ReadInt16(); + short second = reader.ReadInt16(); + extentionData.TimeStamp = new DateTime(year, month, day, hour, minute, second); + extentionData.JobID = reader.ReadString(41); + extentionData.JobTime = new TimeSpan( + hours: reader.ReadInt16(), + minutes: reader.ReadInt16(), + seconds: reader.ReadInt16() + ); + extentionData.SoftwareID = reader.ReadString(41); + extentionData.SoftwareVersion = reader.ReadBytes(3); + extentionData.KeyColor = reader.ReadInt32(); + extentionData.PixelAspectRatio = reader.ReadInt32(); + extentionData.GammaValue = reader.ReadInt32(); + extentionData.ColorCorrectionOffset = reader.ReadInt32(); + extentionData.PostageStampOffset = reader.ReadInt32(); + extentionData.ScanLineOffset = reader.ReadInt32(); + extentionData.AttributesType = reader.ReadByte(); + DebugLogExtentionData(extentionData); + return extentionData; + } + } + return default; + } + + [Conditional("DEBUG")] + [DebuggerHidden] + [DebuggerStepThrough] + private static void DebugLogExtentionData(TGAExtentionData extentionData) + { + Debug.WriteLine("-------Extention Data-------", category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Author Name: {0}", args: extentionData.AuthorName), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Author Comment: {0}", args: extentionData.AuthorComment), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Time Stamp: {0}", args: extentionData.TimeStamp), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Job ID: {0}", args: extentionData.JobID), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Job Time: {0}", args: extentionData.JobTime), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("SoftwareID: {0}", args: extentionData.SoftwareID), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Software Version: {0}.{1}.{2}", extentionData.SoftwareVersion[0], extentionData.SoftwareVersion[1], extentionData.SoftwareVersion[2]), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Key Color: {0}", args: extentionData.KeyColor), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Pixel Aspect Ratio: {0}", args: extentionData.PixelAspectRatio), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Gamma Value: {0}", args: extentionData.GammaValue), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Color Correction Offset: {0}", args: extentionData.ColorCorrectionOffset), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Postage Stamp Offset: {0}", args: extentionData.PostageStampOffset), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Scan Line Offset: {0}", args: extentionData.ScanLineOffset), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Attributes Type: {0}", args: extentionData.AttributesType), category: nameof(TGAReader)); + Debug.WriteLine("----------------------------", category: nameof(TGAReader)); + } + + [Conditional("DEBUG")] + [DebuggerHidden] + [DebuggerStepThrough] + private static void DebugLogHeader(TGAHeader header) + { + Debug.WriteLine("------Header Data------", category: nameof(TGAReader)); + Debug.WriteLine(string.Format("ID length: {0}", args: header.Id.Length), category: nameof(TGAReader)); + Debug.WriteLineIf(header.Id.Length > 0, $"ID: {header.Id}", category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Colourmap type: {0}", args: header.Colormap.Type), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Image type: {0}", args: header.DataTypeCode), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Colour map offset: {0}", args: header.Colormap.Origin), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Colour map length: {0}", args: header.Colormap.Length), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Colour map depth: {0}", args: header.Colormap.Depth), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("X origin: {0}", args: header.Origin.X), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Y origin: {0}", args: header.Origin.Y), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Width: {0}", args: header.Width), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Height: {0}", args: header.Height), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Bits per pixel: {0}", args: header.BitsPerPixel), category: nameof(TGAReader)); + Debug.WriteLine(string.Format("Descriptor: {0}", args: header.ImageDescriptor), category: nameof(TGAReader)); + Debug.WriteLine("-----------------------", category: nameof(TGAReader)); + } + + [Conditional("DEBUG")] + [DebuggerHidden] + [DebuggerStepThrough] + private static void DebugLogFooter(TGAFooter footer) + { + Debug.WriteLine("-------Footer Data-------", category: nameof(TGAReader)); + Debug.WriteLine($"Extension Data Offset: {footer.ExtensionDataOffset:x}", category: nameof(TGAReader)); + Debug.WriteLine($"Developer Area Data Offset: {footer.DeveloperAreaDataOffset:x}", category: nameof(TGAReader)); + Debug.WriteLine("-----------------------", category: nameof(TGAReader)); + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGASerializer.cs b/PCK-Studio/Classes/IO/TGA/TGASerializer.cs new file mode 100644 index 00000000..ce018242 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGASerializer.cs @@ -0,0 +1,32 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System.IO; +using System.Drawing; + +namespace PckStudio.IO.TGA +{ + internal static class TGASerializer + { + private static TGAWriter writer = new TGAWriter(); + + public static void SerializeToStream(ref Stream stream, Image image) + { + writer.WriteToStream(stream, image); + } + } +} \ No newline at end of file diff --git a/PCK-Studio/Classes/IO/TGA/TGAWriter.cs b/PCK-Studio/Classes/IO/TGA/TGAWriter.cs new file mode 100644 index 00000000..ff0b5475 --- /dev/null +++ b/PCK-Studio/Classes/IO/TGA/TGAWriter.cs @@ -0,0 +1,143 @@ +/* Copyright (c) 2022-present miku-666 + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1.The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. +**/ +using System; +using System.IO; +using System.Drawing; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Runtime.InteropServices; +using System.Text; +using OMI; +using System.Windows.Forms; +using DiscordRPC; + +namespace PckStudio.IO.TGA +{ + internal class TGAWriter + { + private Bitmap _bitmap; + private int extensionDataOffset = 0; + + public TGAWriter() + { + } + + private void WriteHeader(EndiannessAwareBinaryWriter writer) + { + writer.Write(new byte[] + { + 0, // header.Id.Length + 0, // colormap type + (byte)TGADataTypeCode.RGB + }); + writer.Write(0); // Colormap.Origin + writer.Write(0); // Colormap.Length + writer.Write(0); // Colormap.Depth + writer.Write(0); // Origin.X + writer.Write(0); // Origin.Y + writer.Write(_bitmap.Width); + writer.Write(_bitmap.Height); + writer.Write(32); // BitsPerPixel + writer.Write(8); // ImageDescriptor + } + + private void WriteImage(EndiannessAwareBinaryWriter writer) + { + _bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); + BitmapData bitmapData = _bitmap.LockBits( + new Rectangle(0, 0, _bitmap.Width, _bitmap.Height), + ImageLockMode.ReadOnly, + PixelFormat.Format32bppArgb); + + byte[] buffer = new byte[_bitmap.Width * _bitmap.Height * 4]; + Marshal.Copy(bitmapData.Scan0, buffer, 0, _bitmap.Width * _bitmap.Height * 4); + writer.Write(buffer); + } + + private void WriteFooter(EndiannessAwareBinaryWriter writer) + { + writer.Write(extensionDataOffset); // extensionDataOffset + writer.Write(0); // developerAreaDataOffset + writer.WriteString(TGAFooter.Signature); + writer.Write((byte)0x2E); + writer.Write((byte)0x00); + } + + private void WriteExtensionData(EndiannessAwareBinaryWriter writer) + { + extensionDataOffset = Convert.ToInt32(writer.BaseStream.Position); + TGAExtentionData extentionData = TGAExtentionData.Create(); + writer.Write(TGAExtentionData.ExtensionSize); + // Author Name + writer.WriteString(extentionData.AuthorName, 41); + // Author Comment + writer.WriteString(extentionData.AuthorComment, 324); + // Timestamp + writer.Write((short)extentionData.TimeStamp.Month); + writer.Write((short)extentionData.TimeStamp.Day); + writer.Write((short)extentionData.TimeStamp.Year); + writer.Write((short)extentionData.TimeStamp.Hour); + writer.Write((short)extentionData.TimeStamp.Minute); + writer.Write((short)extentionData.TimeStamp.Second); + // Job id + writer.WriteString(extentionData.JobID, 41); + // Job time + writer.Write((short)extentionData.JobTime.Hours); + writer.Write((short)extentionData.JobTime.Minutes); + writer.Write((short)extentionData.JobTime.Seconds); + // Software Id + writer.WriteString(extentionData.SoftwareID, 41); + // Software version + writer.Write(extentionData.SoftwareVersion, 0, 3); + // Key color + writer.Write(extentionData.KeyColor); + // Pixel aspect ratio + writer.Write(extentionData.PixelAspectRatio); + // Gamma value + writer.Write(extentionData.GammaValue); + // Color correction offset + writer.Write(extentionData.ColorCorrectionOffset); + // Postage stamp offset + writer.Write(extentionData.PostageStampOffset); + // Scan line offset + writer.Write(extentionData.ScanLineOffset); + // Attributes type + writer.Write(extentionData.AttributesType); + } + + public void WriteToStream(Stream stream, Image image) + { + _bitmap = new Bitmap(image); + using (var writer = new EndiannessAwareBinaryWriter(stream, Encoding.ASCII, leaveOpen: true, Endianness.LittleEndian)) + { + WriteHeader(writer); + WriteImage(writer); + WriteExtensionData(writer); + WriteFooter(writer); + } + } + + public void WriteToFile(string filename, Image image) + { + using (var fs = File.OpenWrite(filename)) + { + WriteToStream(fs, image); + } + } + } +} diff --git a/PCK-Studio/Extensions/PckFileDataExtensions.cs b/PCK-Studio/Extensions/PckFileDataExtensions.cs index 9488fdcb..7427a0d6 100644 --- a/PCK-Studio/Extensions/PckFileDataExtensions.cs +++ b/PCK-Studio/Extensions/PckFileDataExtensions.cs @@ -9,6 +9,7 @@ using System.Text; using System.Threading.Tasks; using OMI.Formats.Pck; using OMI.Workers; +using PckStudio.IO.TGA; namespace PckStudio.Extensions { @@ -30,7 +31,10 @@ namespace PckStudio.Extensions { try { - return Image.FromStream(stream); + if (Path.GetExtension(file.Filename) == ".tga") + return TGADeserializer.DeserializeFromStream(stream); + else + return Image.FromStream(stream); } catch(Exception ex) { diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index d8fb5d75..b8d13042 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -571,11 +571,7 @@ namespace PckStudio case PckFileType.CapeFile: case PckFileType.TextureFile: { - // TODO: Add tga support - if (Path.GetExtension(file.Filename) == ".tga") break; - using MemoryStream stream = new MemoryStream(file.Data); - - var img = Image.FromStream(stream); + Image img = file.GetTexture(); if (img.RawFormat != ImageFormat.Jpeg || img.RawFormat != ImageFormat.Png) { @@ -595,7 +591,6 @@ namespace PckStudio Debug.WriteLine(string.Format("An error occured of type: {0} with message: {1}", ex.GetType(), ex.Message), "Exception"); } - if ((file.Filename.StartsWith("res/textures/blocks/") || file.Filename.StartsWith("res/textures/items/")) && file.Filetype == PckFileType.TextureFile && !file.IsMipmappedFile()) @@ -1953,7 +1948,7 @@ namespace PckStudio private void addTextureToolStripMenuItem_Click(object sender, EventArgs e) { using OpenFileDialog fileDialog = new OpenFileDialog(); - fileDialog.Filter = "Texture File(*.png;*.tga)|*.png;*.tga"; + fileDialog.Filter = "Texture File(*.png,*.tga)|*.png;*.tga"; if (fileDialog.ShowDialog() == DialogResult.OK) { using TextPrompt renamePrompt = new TextPrompt(Path.GetFileName(fileDialog.FileName)); @@ -1997,9 +1992,6 @@ namespace PckStudio string textureExtension = Path.GetExtension(file.Filename); - // TGA is not yet supported - if (textureExtension == ".tga") return; - using NumericPrompt numericPrompt = new NumericPrompt(0); numericPrompt.Minimum = 1; numericPrompt.Maximum = 4; // 5 is the presumed max MipMap level @@ -2018,7 +2010,7 @@ namespace PckStudio PckFileData MipMappedFile = new PckFileData(mippedPath, PckFileType.TextureFile); - Image originalTexture = Image.FromStream(new MemoryStream(file.Data)); + Image originalTexture = file.GetTexture(); int NewWidth = Math.Max(originalTexture.Width / (int)Math.Pow(2, i - 1), 1); int NewHeight = Math.Max(originalTexture.Height / (int)Math.Pow(2, i - 1), 1); diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index 112dceb3..47a63e0b 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -133,11 +133,14 @@ + + + @@ -245,7 +248,14 @@ WiiUPanel.cs - + + + + + + + + Form From 0198beb6e86c4d83763202bc2b0296ca2d53e292 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:06:35 +0100 Subject: [PATCH 7/9] MainForm - Fix 3dst export crashing when file is tga image --- PCK-Studio/MainForm.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index b8d13042..243ebf3d 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -2060,15 +2060,12 @@ namespace PckStudio saveFileDialog.DefaultExt = ".3dst"; if (saveFileDialog.ShowDialog() == DialogResult.OK) { - using (var ms = new MemoryStream(file.Data)) - { - Image img = Image.FromStream(ms); + Image img = file.GetTexture(); var writer = new _3DSTextureWriter(img); writer.WriteToFile(saveFileDialog.FileName); } } } - } private void addMultipleEntriesToolStripMenuItem1_Click(object sender, EventArgs e) { From 9ab906920d4361fbed394d4bd6e2e451cd26641c Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:07:34 +0100 Subject: [PATCH 8/9] MainForm - Mark SubPck functions as obsolete --- PCK-Studio/MainForm.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index 243ebf3d..bb92cdc8 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -990,6 +990,7 @@ namespace PckStudio } } + [Obsolete()] bool IsSubPCKNode(string nodePath, string extention = ".pck") { // written by miku, implemented and modified by MattNL @@ -1018,6 +1019,7 @@ namespace PckStudio return childNodes; } + [Obsolete()] TreeNode GetSubPCK(string childPath) { string parentPath = childPath.Replace('\\', '/'); @@ -1036,6 +1038,7 @@ namespace PckStudio return null; } + [Obsolete()] void RebuildSubPCK(string childPath) { // Support for if a file is edited within a nested PCK File (AKA SubPCK) @@ -2061,11 +2064,11 @@ namespace PckStudio if (saveFileDialog.ShowDialog() == DialogResult.OK) { Image img = file.GetTexture(); - var writer = new _3DSTextureWriter(img); - writer.WriteToFile(saveFileDialog.FileName); - } + var writer = new _3DSTextureWriter(img); + writer.WriteToFile(saveFileDialog.FileName); } } + } private void addMultipleEntriesToolStripMenuItem1_Click(object sender, EventArgs e) { From 4642d58383d27fc1b8984784528d9225606e5372 Mon Sep 17 00:00:00 2001 From: miku-666 <74728189+NessieHax@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:47:44 +0100 Subject: [PATCH 9/9] MainForm - Use explicit type when type cannot be inferred --- PCK-Studio/MainForm.cs | 84 +++++++++++++++++++++--------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/PCK-Studio/MainForm.cs b/PCK-Studio/MainForm.cs index bb92cdc8..e091ebd1 100644 --- a/PCK-Studio/MainForm.cs +++ b/PCK-Studio/MainForm.cs @@ -331,7 +331,7 @@ namespace PckStudio _ = root ?? throw new ArgumentNullException(nameof(root)); if (!path.Contains(seperator)) { - var finalNode = CreateNode(path); + TreeNode finalNode = CreateNode(path); root.Add(finalNode); return finalNode; } @@ -345,7 +345,7 @@ namespace PckStudio private void BuildPckTreeView(TreeNodeCollection root, PckFile pckFile) { - foreach (var file in pckFile.GetFiles()) + foreach (PckFileData file in pckFile.GetFiles()) { // fix any file paths that may be incorrect //if (file.Filename.StartsWith(parentPath)) @@ -410,10 +410,10 @@ namespace PckStudio isMapIcons || isAdditionalMapIcons || isXPOrbs || isExplosions || isBanners ) { - var img = file.GetTexture(); + Image img = file.GetTexture(); var tile_size = new Size(); - var banner_scale = img.Width / Resources.banners_atlas.Width; + int banner_scale = img.Width / Resources.banners_atlas.Width; if (isBanners) { @@ -424,21 +424,21 @@ namespace PckStudio tile_size = new Size(42 * banner_scale, 41 * banner_scale); } - // most atlases have 4 columns - var columnCount = isBanners ? 6 : 4; + // most atlases have 4 columns + int columnCount = isBanners ? 6 : 4; if (isTerrain || isItems || isParticles || isPaintings) columnCount = 16; if (!isBanners) { - var resolution = img.Width / columnCount; + int resolution = img.Width / columnCount; tile_size = new Size(resolution, resolution); } var viewer = new TextureAtlasEditor(currentPCK, file.Filename, img, tile_size); if (viewer.ShowDialog() == DialogResult.OK) { - var texture = viewer.FinalTexture; + Image texture = viewer.FinalTexture; if(isBanners) { var graphicsConfig = new GraphicsConfig() @@ -450,7 +450,7 @@ namespace PckStudio var _img = new Bitmap((Resources.banners_atlas.Width + 4) * banner_scale, (Resources.banners_atlas.Height + 1) * banner_scale); - using (var g = Graphics.FromImage(_img)) + using (Graphics g = Graphics.FromImage(_img)) { g.ApplyConfig(graphicsConfig); g.DrawImage(texture, 0, 0, texture.Width, texture.Height); @@ -468,7 +468,7 @@ namespace PckStudio if (!file.Filename.StartsWith("res/textures/blocks/") && !file.Filename.StartsWith("res/textures/items/")) return; - var animation = AnimationHelper.GetAnimationFromFile(file); + Animation animation = AnimationHelper.GetAnimationFromFile(file); using (AnimationEditor animationEditor = new AnimationEditor(animation, Path.GetFileNameWithoutExtension(file.Filename))) { if (animationEditor.ShowDialog(this) == DialogResult.OK) @@ -521,7 +521,7 @@ namespace PckStudio return; } - var img = file.GetTexture(); + Image img = file.GetTexture(); using var skinViewer = new SkinPreview(img, file.GetProperty("ANIM", SkinANIM.FromString)); skinViewer.ShowDialog(this); } @@ -633,7 +633,7 @@ namespace PckStudio if (file.PropertyCount > 0) { using var fs = File.CreateText($"{outFilePath}.txt"); - foreach (var property in file.GetProperties()) + foreach (KeyValuePair property in file.GetProperties()) { fs.WriteLine($"{property.Key}: {property.Value}"); } @@ -674,7 +674,7 @@ namespace PckStudio } else { - foreach (var _file in currentPCK.GetFiles()) + foreach (PckFileData _file in currentPCK.GetFiles()) { if (_file.Filename.StartsWith(selectedFolder)) { @@ -686,7 +686,7 @@ namespace PckStudio private void extractToolStripMenuItem_Click(object sender, EventArgs e) { - var node = treeViewMain.SelectedNode; + TreeNode node = treeViewMain.SelectedNode; if (node == null) { @@ -814,7 +814,7 @@ namespace PckStudio private void deleteFileToolStripMenuItem_Click(object sender, EventArgs e) { - var node = treeViewMain.SelectedNode; + TreeNode node = treeViewMain.SelectedNode; if (node == null) return; @@ -861,7 +861,7 @@ namespace PckStudio else // folders { node.Text = diag.NewText; - foreach (var childNode in GetAllChildNodes(node.Nodes)) + foreach (TreeNode childNode in GetAllChildNodes(node.Nodes)) { if (childNode.Tag is PckFileData folderFile) { @@ -951,7 +951,7 @@ namespace PckStudio return; } - var file = CreateNewAudioFile(LittleEndianCheckBox.Checked); + PckFileData file = CreateNewAudioFile(LittleEndianCheckBox.Checked); AudioEditor diag = new AudioEditor(file, LittleEndianCheckBox.Checked); if (diag.ShowDialog(this) == DialogResult.OK) { @@ -977,7 +977,7 @@ namespace PckStudio $"res/textures/{Animation.GetCategoryName(diag.Category)}/{diag.SelectedTile}.png", PckFileType.TextureFile); - var animation = AnimationHelper.GetAnimationFromFile(file); + Animation animation = AnimationHelper.GetAnimationFromFile(file); using AnimationEditor animationEditor = new AnimationEditor(animation, diag.SelectedTile); if (animationEditor.ShowDialog() == DialogResult.OK) @@ -1026,7 +1026,7 @@ namespace PckStudio Debug.WriteLine(parentPath); string[] s = parentPath.Split('/'); Debug.WriteLine(s.Length); - foreach (var node in s) + foreach (string node in s) { TreeNode parent = treeViewMain.Nodes.Find(node, true)[0]; if (parent.TryGetTagData(out PckFileData f) && @@ -1290,7 +1290,7 @@ namespace PckStudio { var pack = new PckFile(3); - var zeroFile = pack.CreateNewFile("0", PckFileType.InfoFile); + PckFileData zeroFile = pack.CreateNewFile("0", PckFileType.InfoFile); zeroFile.AddProperty("PACKID", packId); zeroFile.AddProperty("PACKVERSION", packVersion); @@ -1308,18 +1308,17 @@ namespace PckStudio private PckFile InitializeTexturePack(int packId, int packVersion, string packName, string res, bool createSkinsPCK) { - var pack = InitializePack(packId, packVersion, packName, createSkinsPCK); + PckFile pack = InitializePack(packId, packVersion, packName, createSkinsPCK); PckFile infoPCK = new PckFile(3); - var icon = infoPCK.CreateNewFile("icon.png", PckFileType.TextureFile); + PckFileData icon = infoPCK.CreateNewFile("icon.png", PckFileType.TextureFile); icon.SetData(Resources.TexturePackIcon, ImageFormat.Png); - var comparison = infoPCK.CreateNewFile("comparison.png", PckFileType.TextureFile); + PckFileData comparison = infoPCK.CreateNewFile("comparison.png", PckFileType.TextureFile); comparison.SetData(Resources.Comparison, ImageFormat.Png); - var texturepackInfo = pack.CreateNewFile($"{res}/{res}Info.pck", PckFileType.TexturePackInfoFile); - + PckFileData texturepackInfo = pack.CreateNewFile($"{res}/{res}Info.pck", PckFileType.TexturePackInfoFile); texturepackInfo.AddProperty("PACKID", "0"); texturepackInfo.AddProperty("DATAPATH", $"{res}Data.pck"); @@ -1330,9 +1329,9 @@ namespace PckStudio private PckFile InitializeMashUpPack(int packId, int packVersion, string packName, string res) { - var pack = InitializeTexturePack(packId, packVersion, packName, res, true); - var gameRuleFile = pack.CreateNewFile("GameRules.grf", PckFileType.GameRulesFile); - var grfFile = new GameRuleFile(); + PckFile pack = InitializeTexturePack(packId, packVersion, packName, res, true); + PckFileData gameRuleFile = pack.CreateNewFile("GameRules.grf", PckFileType.GameRulesFile); + GameRuleFile grfFile = new GameRuleFile(); grfFile.AddRule("MapOptions", new KeyValuePair("seed", "0"), new KeyValuePair("baseSaveName", string.Empty), @@ -1450,7 +1449,7 @@ namespace PckStudio if (ofd.ShowDialog() == DialogResult.OK && sfd.ShowDialog() == DialogResult.OK) { PckFile pckfile = null; - using (var fs = File.OpenRead(ofd.FileName)) + using (FileStream fs = File.OpenRead(ofd.FileName)) { try { @@ -1476,7 +1475,7 @@ namespace PckStudio //attempts to generate reimportable metadata file out of minefiles metadata string metaData = ""; - foreach (var entry in file.GetProperties()) + foreach (KeyValuePair entry in file.GetProperties()) { metaData += $"{entry.Key}: {entry.Value}{Environment.NewLine}"; } @@ -1828,9 +1827,9 @@ namespace PckStudio { pckOpen.Image = Resources.pckDrop; string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); - foreach (var file in files) + foreach (string file in files) { - var ext = Path.GetExtension(file); + string ext = Path.GetExtension(file); if (ext.Equals(".pck", StringComparison.CurrentCultureIgnoreCase)) e.Effect = DragDropEffects.Copy; return; @@ -1963,7 +1962,7 @@ namespace PckStudio MessageBox.Show($"'{renamePrompt.NewText}' already exists.", "Import failed", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } - var file = currentPCK.CreateNewFile(renamePrompt.NewText, PckFileType.TextureFile, () => File.ReadAllBytes(fileDialog.FileName)); + PckFileData file = currentPCK.CreateNewFile(renamePrompt.NewText, PckFileType.TextureFile, () => File.ReadAllBytes(fileDialog.FileName)); BuildMainTreeView(); wasModified = true; } @@ -2043,7 +2042,7 @@ namespace PckStudio MessageBox.Show("A color table file already exists in this PCK and a new one cannot be created.", "Operation aborted"); return; } - var newColorFile = currentPCK.CreateNewFile("colours.col", PckFileType.ColourTableFile); + PckFileData newColorFile = currentPCK.CreateNewFile("colours.col", PckFileType.ColourTableFile); newColorFile.SetData(Resources.tu69colours); BuildMainTreeView(); } @@ -2078,7 +2077,7 @@ namespace PckStudio { if (input.ShowDialog(this) == DialogResult.OK) { - foreach (var line in input.TextOutput) + foreach (string line in input.TextOutput) { int idx = line.IndexOf(' '); if (idx == -1 || line.Length - 1 == idx) @@ -2098,7 +2097,7 @@ namespace PckStudio if (treeViewMain.SelectedNode.TryGetTagData(out PckFileData file) && file.Filetype == PckFileType.SkinFile) { - foreach (var p in file.GetProperties()) + foreach (KeyValuePair p in file.GetProperties()) { if (p.Key == "BOX" || p.Key == "OFFSET") file.SetProperty(file.GetPropertyIndex(p), new KeyValuePair(p.Key, p.Value.Replace(',', '.'))); @@ -2133,13 +2132,13 @@ namespace PckStudio { if (treeViewMain.SelectedNode.TryGetTagData(out PckFileData file)) { - var props = file.GetProperties().Select(p => p.Key + " " + p.Value); - using (var input = new MultiTextPrompt(props.ToArray())) + string[] props = file.GetProperties().Select(p => p.Key + " " + p.Value).ToArray(); + using (var input = new MultiTextPrompt(props)) { if (input.ShowDialog(this) == DialogResult.OK) { file.ClearProperties(); - foreach (var line in input.TextOutput) + foreach (string line in input.TextOutput) { int idx = line.IndexOf(' '); if (idx == -1 || line.Length - 1 == idx) @@ -2312,10 +2311,11 @@ namespace PckStudio [Obsolete] // the move functions are to eventually be removed in favor of drag and drop private void moveFile(int amount) { - if (treeViewMain.SelectedNode is not TreeNode t || t.Tag is null) return; + if (treeViewMain.SelectedNode is not TreeNode t || t.Tag is not PckFileData) + return; - var file = t.Tag as PckFileData; - var path = t.FullPath; + PckFileData file = t.Tag as PckFileData; + string path = t.FullPath; // skin and cape files only if (!(file.Filetype == PckFileType.SkinFile || file.Filetype == PckFileType.CapeFile)) return;