Add ShpRemastered sprite loader.

This commit is contained in:
Paul Chote
2020-10-08 22:42:06 +01:00
committed by reaperrr
parent f341c9a8a6
commit f51603e440
2 changed files with 129 additions and 0 deletions

View File

@@ -0,0 +1,117 @@
#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;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using ICSharpCode.SharpZipLib.Zip;
using OpenRA.Graphics;
using OpenRA.Mods.Common.SpriteLoaders;
using OpenRA.Primitives;
namespace OpenRA.Mods.Cnc.SpriteLoaders
{
public class ShpRemasteredLoader : ISpriteLoader
{
public static bool IsShpRemastered(Stream s)
{
var start = s.Position;
var isZipFile = s.ReadUInt32() == 0x04034B50;
s.Position = start;
return isZipFile;
}
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames, out TypeDictionary metadata)
{
metadata = null;
if (!IsShpRemastered(s))
{
frames = null;
return false;
}
frames = new ShpRemasteredSprite(s).Frames.ToArray();
return true;
}
}
public class ShpRemasteredSprite
{
static readonly Regex FilenameRegex = new Regex(@"^(?<prefix>.+?[\-_])(?<frame>\d{4})\.tga$");
static readonly Regex MetaRegex = new Regex(@"^\{""size"":\[(?<width>\d+),(?<height>\d+)\],""crop"":\[(?<left>\d+),(?<top>\d+),(?<right>\d+),(?<bottom>\d+)\]\}$");
int ParseGroup(Match match, string group)
{
return int.Parse(match.Groups[group].Value);
}
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
public ShpRemasteredSprite(Stream stream)
{
var container = new ZipFile(stream);
string framePrefix = null;
var frameCount = 0;
foreach (ZipEntry entry in container)
{
var match = FilenameRegex.Match(entry.Name);
if (!match.Success)
continue;
var prefix = match.Groups["prefix"].Value;
if (framePrefix == null)
framePrefix = prefix;
if (prefix != framePrefix)
throw new InvalidDataException("Frame prefix mismatch: `{0}` != `{1}`".F(prefix, framePrefix));
frameCount = Math.Max(frameCount, int.Parse(match.Groups["frame"].Value) + 1);
}
var frames = new ISpriteFrame[frameCount];
for (var i = 0; i < frames.Length; i++)
{
var tgaEntry = container.GetEntry("{0}{1:D4}.tga".F(framePrefix, i));
// Blank frame
if (tgaEntry == null)
{
frames[i] = new TgaSprite.TgaFrame();
continue;
}
var metaEntry = container.GetEntry("{0}{1:D4}.meta".F(framePrefix, i));
using (var tgaStream = container.GetInputStream(tgaEntry))
{
var metaStream = metaEntry != null ? container.GetInputStream(metaEntry) : null;
if (metaStream != null)
{
var meta = MetaRegex.Match(metaStream.ReadAllText());
var crop = Rectangle.FromLTRB(
ParseGroup(meta, "left"), ParseGroup(meta, "top"),
ParseGroup(meta, "right"), ParseGroup(meta, "bottom"));
var frameSize = new Size(ParseGroup(meta, "width"), ParseGroup(meta, "height"));
frames[i] = new TgaSprite.TgaFrame(tgaStream, frameSize, crop);
metaStream.Dispose();
}
else
frames[i] = new TgaSprite.TgaFrame(tgaStream);
}
}
Frames = frames.AsReadOnly();
}
}
}

View File

@@ -75,6 +75,11 @@ namespace OpenRA.Mods.Common.SpriteLoaders
public byte[] Data { get; private set; }
public bool DisableExportPadding { get { return false; } }
public TgaFrame()
{
Data = new byte[0];
}
public TgaFrame(Stream stream)
{
using (var tga = Targa.Create(stream, new PfimConfig()))
@@ -90,6 +95,13 @@ namespace OpenRA.Mods.Common.SpriteLoaders
}
}
}
public TgaFrame(Stream stream, Size frameSize, Rectangle frameWindow)
: this(stream)
{
FrameSize = frameSize;
Offset = 0.5f * new float2(frameWindow.Left + frameWindow.Right - FrameSize.Width, frameWindow.Top + frameWindow.Bottom - FrameSize.Height);
}
}
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }