Use family palettes for PCX textures

This commit is contained in:
Jarrod Doyle 2024-08-12 19:02:20 +01:00
parent c14f74b108
commit 21b018298c
Signed by: Jayrude
GPG Key ID: 38B57B16E7C0ADF7
1 changed files with 46 additions and 31 deletions

View File

@ -1,20 +1,55 @@
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Numerics;
using System.Text; using System.Text;
using Godot;
namespace KeepersCompound.TMV; namespace KeepersCompound.TMV;
public partial class TextureLoader public partial class TextureLoader
{ {
// TODO: Support more types of PCX just in case // TODO: Support more types of PCX just in case
// TODO: We need to load the palette from an external file!!!
// References: // References:
// - https://www.fileformat.info/format/pcx/egff.htm // - https://www.fileformat.info/format/pcx/egff.htm
// - http://www.fysnet.net/pcxfile.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 MemoryStream stream = new(File.ReadAllBytes(path));
using BinaryReader reader = new(stream, Encoding.UTF8, false); using BinaryReader reader = new(stream, Encoding.UTF8, false);
@ -23,17 +58,16 @@ public partial class TextureLoader
var version = reader.ReadByte(); var version = reader.ReadByte();
var compression = reader.ReadByte(); var compression = reader.ReadByte();
var bytesPerPixel = reader.ReadByte(); var bytesPerPixel = reader.ReadByte();
var min = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); var min = ReadVec2(reader);
var max = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); var max = ReadVec2(reader);
var dpi = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); var dpi = ReadVec2(reader);
var headerPalette = reader.ReadBytes(48); var headerPalette = reader.ReadBytes(48);
reader.ReadByte(); reader.ReadByte();
var numPlanes = reader.ReadByte(); var numPlanes = reader.ReadByte();
var bytesPerRow = reader.ReadUInt16(); var bytesPerRow = reader.ReadUInt16();
var paletteMode = reader.ReadUInt16(); var paletteMode = reader.ReadUInt16();
var dpiSrc = new Vector2(reader.ReadUInt16(), reader.ReadUInt16()); var dpiSrc = ReadVec2(reader);
reader.ReadBytes(54); reader.ReadBytes(54);
var dataOffset = stream.Position;
// Validation // Validation
if (tag != 0x0A) if (tag != 0x0A)
@ -54,13 +88,12 @@ public partial class TextureLoader
throw new System.Exception("Unsupported bpp/plane format"); throw new System.Exception("Unsupported bpp/plane format");
} }
var palette = LoadPcxPalette(reader); var palette = LoadFamilyPalette(path.GetBaseDir());
// Read pixels // Read run length encoded pixel Data
stream.Seek(dataOffset, SeekOrigin.Begin);
var width = (int)(max.X - min.X + 1); var width = (int)(max.X - min.X + 1);
var height = (int)(max.Y - min.Y + 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++) for (var y = 0; y < height; y++)
{ {
var x = 0; var x = 0;
@ -85,24 +118,6 @@ public partial class TextureLoader
} }
} }
return Godot.ImageTexture.CreateFromImage(image); return 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;
} }
} }