From 21b018298c4fc75a02a65b57b77451debb79c4db Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Mon, 12 Aug 2024 19:02:20 +0100 Subject: [PATCH] Use family palettes for PCX textures --- project/code/TMV/TextureLoader.Pcx.cs | 77 ++++++++++++++++----------- 1 file changed, 46 insertions(+), 31 deletions(-) diff --git a/project/code/TMV/TextureLoader.Pcx.cs b/project/code/TMV/TextureLoader.Pcx.cs index 34f490a..449bd9d 100644 --- a/project/code/TMV/TextureLoader.Pcx.cs +++ b/project/code/TMV/TextureLoader.Pcx.cs @@ -1,20 +1,55 @@ using System.IO; using System.Linq; -using System.Numerics; using System.Text; +using Godot; namespace KeepersCompound.TMV; public partial class TextureLoader { // TODO: Support more types of PCX just in case - // TODO: We need to load the palette from an external file!!! // References: // - https://www.fileformat.info/format/pcx/egff.htm // - http://www.fysnet.net/pcxfile.htm - private static Godot.ImageTexture LoadPcx(string path) + private static ImageTexture LoadPcx(string path) { + static Color[] LoadFamilyPalette(string famPath) + { + var numColors = 256; + var bytesPerColor = 3; + var paletteSize = numColors * bytesPerColor; + var palette = new Color[numColors]; + + var options = new EnumerationOptions + { + MatchCasing = MatchCasing.CaseInsensitive + }; + var paths = Directory.GetFiles(famPath, "full.pcx", options); + if (paths.Length != 0) + { + var palettePath = paths[0]; + using MemoryStream stream = new(File.ReadAllBytes(palettePath)); + using BinaryReader reader = new(stream, Encoding.UTF8, false); + stream.Seek(-paletteSize, SeekOrigin.End); + + for (var i = 0; i < numColors; i++) + { + var r = reader.ReadByte() / 255.0f; + var g = reader.ReadByte() / 255.0f; + var b = reader.ReadByte() / 255.0f; + palette[i] = new Color(r, g, b); + } + } + + return palette; + } + + static System.Numerics.Vector2 ReadVec2(BinaryReader reader) + { + return new(reader.ReadUInt16(), reader.ReadUInt16()); + } + using MemoryStream stream = new(File.ReadAllBytes(path)); using BinaryReader reader = new(stream, Encoding.UTF8, false); @@ -23,17 +58,16 @@ public partial class TextureLoader var version = reader.ReadByte(); var compression = reader.ReadByte(); var bytesPerPixel = reader.ReadByte(); - var min = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); - var max = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); - var dpi = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); + var min = ReadVec2(reader); + var max = ReadVec2(reader); + var dpi = ReadVec2(reader); var headerPalette = reader.ReadBytes(48); reader.ReadByte(); var numPlanes = reader.ReadByte(); var bytesPerRow = reader.ReadUInt16(); var paletteMode = reader.ReadUInt16(); - var dpiSrc = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); + var dpiSrc = ReadVec2(reader); reader.ReadBytes(54); - var dataOffset = stream.Position; // Validation if (tag != 0x0A) @@ -54,13 +88,12 @@ public partial class TextureLoader throw new System.Exception("Unsupported bpp/plane format"); } - var palette = LoadPcxPalette(reader); + var palette = LoadFamilyPalette(path.GetBaseDir()); - // Read pixels - stream.Seek(dataOffset, SeekOrigin.Begin); + // Read run length encoded pixel Data var width = (int)(max.X - min.X + 1); var height = (int)(max.Y - min.Y + 1); - var image = Godot.Image.Create(width, height, false, Godot.Image.Format.Rgba8); + var image = Image.Create(width, height, false, Image.Format.Rgba8); for (var y = 0; y < height; y++) { var x = 0; @@ -85,24 +118,6 @@ public partial class TextureLoader } } - return Godot.ImageTexture.CreateFromImage(image); - } - - private static Godot.Color[] LoadPcxPalette(BinaryReader reader) - { - var numColors = 256; - var bytesPerColor = 3; - var paletteSize = numColors * bytesPerColor; - reader.BaseStream.Seek(-paletteSize, SeekOrigin.End); - - var palette = new Godot.Color[numColors]; - for (var i = 0; i < numColors; i++) - { - var r = reader.ReadByte() / 255.0f; - var g = reader.ReadByte() / 255.0f; - var b = reader.ReadByte() / 255.0f; - palette[i] = new Godot.Color(r, g, b); - } - return palette; + return ImageTexture.CreateFromImage(image); } } \ No newline at end of file