diff --git a/AUTHORS b/AUTHORS index 3cd8f10102..7220de3846 100644 --- a/AUTHORS +++ b/AUTHORS @@ -191,6 +191,9 @@ distributed under MIT License. Using ANGLE distributed under the BS3 3-Clause license. +Using Pfim developed by Nick Babcock +distributed under the MIT license. + This site or product includes IP2Location LITE data available from http://www.ip2location.com. diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 70f8cb959c..cf243e0eb1 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -29,6 +29,7 @@ + diff --git a/OpenRA.Mods.Common/SpriteLoaders/DdsLoader.cs b/OpenRA.Mods.Common/SpriteLoaders/DdsLoader.cs new file mode 100644 index 0000000000..60e17383d6 --- /dev/null +++ b/OpenRA.Mods.Common/SpriteLoaders/DdsLoader.cs @@ -0,0 +1,80 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; +using Pfim; + +namespace OpenRA.Mods.Common.SpriteLoaders +{ + public class DdsLoader : ISpriteLoader + { + public static bool IsDds(Stream s) + { + var start = s.Position; + var isDds = s.ReadUInt32() == 0x20534444; + s.Position = start; + + return isDds; + } + + public bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata) + { + metadata = null; + if (!IsDds(s)) + { + frames = null; + return false; + } + + frames = new DdsSprite(s).Frames.ToArray(); + return true; + } + } + + public class DdsSprite + { + class DdsFrame : ISpriteFrame + { + public SpriteFrameType Type { get; private set; } + public Size Size { get; private set; } + public Size FrameSize { get { return Size; } } + public float2 Offset { get { return float2.Zero; } } + public byte[] Data { get; private set; } + public bool DisableExportPadding { get { return false; } } + + public DdsFrame(Stream stream) + { + using (var dds = Dds.Create(stream, new PfimConfig())) + { + Size = new Size(dds.Width, dds.Height); + Data = dds.Data; + switch (dds.Format) + { + // SpriteFrameType refers to the channel byte order, which is reversed from the little-endian bit order + case ImageFormat.Rgba32: Type = SpriteFrameType.Bgra32; break; + case ImageFormat.Rgb24: Type = SpriteFrameType.Bgr24; break; + default: throw new InvalidDataException("Unhandled ImageFormat {0}".F(dds.Format)); + } + } + } + } + + public IReadOnlyList Frames { get; private set; } + + public DdsSprite(Stream stream) + { + Frames = new ISpriteFrame[] { new DdsFrame(stream) }.AsReadOnly(); + } + } +} diff --git a/OpenRA.Mods.Common/SpriteLoaders/TgaLoader.cs b/OpenRA.Mods.Common/SpriteLoaders/TgaLoader.cs new file mode 100644 index 0000000000..bd05f7fbbe --- /dev/null +++ b/OpenRA.Mods.Common/SpriteLoaders/TgaLoader.cs @@ -0,0 +1,102 @@ +#region Copyright & License Information +/* + * Copyright 2007-2020 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.IO; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Primitives; +using Pfim; + +namespace OpenRA.Mods.Common.SpriteLoaders +{ + public class TgaLoader : ISpriteLoader + { + public static bool IsTga(Stream s) + { + var start = s.Position; + try + { + // Require true-color images + s.Position += 1; + var colorMapType = s.ReadUInt8(); + if (colorMapType != 0) + return false; + + var imageType = s.ReadUInt8(); + if (imageType != 2) + return false; + + var colorMapOffsetAndSize = s.ReadUInt32(); + if (colorMapOffsetAndSize != 0) + return false; + + var colorMapBits = s.ReadUInt8(); + if (colorMapBits != 0) + return false; + + return true; + } + finally + { + s.Position = start; + } + } + + public bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata) + { + metadata = null; + if (!IsTga(s)) + { + frames = null; + return false; + } + + frames = new TgaSprite(s).Frames.ToArray(); + return true; + } + } + + public class TgaSprite + { + public class TgaFrame : ISpriteFrame + { + public SpriteFrameType Type { get; private set; } + public Size Size { get; private set; } + public Size FrameSize { get; private set; } + public float2 Offset { get; private set; } + public byte[] Data { get; private set; } + public bool DisableExportPadding { get { return false; } } + + public TgaFrame(Stream stream) + { + using (var tga = Targa.Create(stream, new PfimConfig())) + { + Size = FrameSize = new Size(tga.Width, tga.Height); + Data = tga.Data; + switch (tga.Format) + { + // SpriteFrameType refers to the channel byte order, which is reversed from the little-endian bit order + case ImageFormat.Rgba32: Type = SpriteFrameType.Bgra32; break; + case ImageFormat.Rgb24: Type = SpriteFrameType.Bgr24; break; + default: throw new InvalidDataException("Unhandled ImageFormat {0}".F(tga.Format)); + } + } + } + } + + public IReadOnlyList Frames { get; private set; } + + public TgaSprite(Stream stream) + { + Frames = new ISpriteFrame[] { new TgaFrame(stream) }.AsReadOnly(); + } + } +}