diff --git a/OpenRA.Game/Graphics/SpriteSource.cs b/OpenRA.Game/Graphics/SpriteSource.cs
index b2e530332e..09c6f35e95 100644
--- a/OpenRA.Game/Graphics/SpriteSource.cs
+++ b/OpenRA.Game/Graphics/SpriteSource.cs
@@ -15,7 +15,7 @@ using OpenRA.FileFormats;
namespace OpenRA.Graphics
{
// TODO: Most of this should be moved into the format parsers themselves.
- public enum SpriteType { Unknown, ShpTS, ShpD2, TmpTD, TmpRA, TmpTS, R8 }
+ public enum SpriteType { Unknown, ShpD2, TmpTD, TmpRA, TmpTS, R8 }
public static class SpriteSource
{
static bool IsTmpRA(Stream s)
@@ -66,43 +66,6 @@ namespace OpenRA.Graphics
return test == sx * sy / 2 + 52;
}
- static bool IsShpTS(Stream s)
- {
- var start = s.Position;
-
- // First word is zero
- if (s.ReadUInt16() != 0)
- {
- s.Position = start;
- return false;
- }
-
- // Sanity Check the image count
- s.Position += 4;
- var imageCount = s.ReadUInt16();
- if (s.Position + 24 * imageCount > s.Length)
- {
- s.Position = start;
- return false;
- }
-
- // Check the size and format flag
- // Some files define bogus frames, so loop until we find a valid one
- s.Position += 4;
- ushort w, h, f = 0;
- byte type;
- do
- {
- w = s.ReadUInt16();
- h = s.ReadUInt16();
- type = s.ReadUInt8();
- }
- while (w == 0 && h == 0 && f++ < imageCount);
-
- s.Position = start;
- return type < 4;
- }
-
static bool IsShpD2(Stream s)
{
var start = s.Position;
@@ -162,9 +125,6 @@ namespace OpenRA.Graphics
public static SpriteType DetectSpriteType(Stream s)
{
- if (IsShpTS(s))
- return SpriteType.ShpTS;
-
if (IsR8(s))
return SpriteType.R8;
@@ -188,8 +148,6 @@ namespace OpenRA.Graphics
var type = DetectSpriteType(s);
switch (type)
{
- case SpriteType.ShpTS:
- return new ShpTSReader(s);
case SpriteType.R8:
return new R8Reader(s);
case SpriteType.TmpRA:
diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index aaad4818f0..83112e9a2d 100644
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -279,7 +279,6 @@
-
diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
index 984386022d..98520994d1 100644
--- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
+++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj
@@ -114,6 +114,7 @@
+
diff --git a/OpenRA.Game/FileFormats/ShpTSReader.cs b/OpenRA.Mods.Common/SpriteLoaders/ShpTSLoader.cs
similarity index 53%
rename from OpenRA.Game/FileFormats/ShpTSReader.cs
rename to OpenRA.Mods.Common/SpriteLoaders/ShpTSLoader.cs
index f45a412323..6471be0aab 100644
--- a/OpenRA.Game/FileFormats/ShpTSReader.cs
+++ b/OpenRA.Mods.Common/SpriteLoaders/ShpTSLoader.cs
@@ -8,15 +8,19 @@
*/
#endregion
+using System;
+using System.Collections.Generic;
using System.Drawing;
using System.IO;
+using System.Linq;
+using OpenRA.FileFormats;
using OpenRA.Graphics;
-namespace OpenRA.FileFormats
+namespace OpenRA.Mods.Common.SpriteLoaders
{
- public class ShpTSReader : ISpriteSource
+ public class ShpTSLoader : ISpriteLoader
{
- class FrameHeader : ISpriteFrame
+ class ShpTSFrame : ISpriteFrame
{
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
@@ -27,7 +31,7 @@ namespace OpenRA.FileFormats
public readonly uint FileOffset;
public readonly byte Format;
- public FrameHeader(Stream stream, Size frameSize)
+ public ShpTSFrame(Stream stream, Size frameSize)
{
var x = stream.ReadUInt16();
var y = stream.ReadUInt16();
@@ -45,20 +49,56 @@ namespace OpenRA.FileFormats
}
}
- public IReadOnlyList Frames { get; private set; }
-
- public ShpTSReader(Stream stream)
+ bool IsShpTS(Stream s)
{
- stream.ReadUInt16();
- var width = stream.ReadUInt16();
- var height = stream.ReadUInt16();
- var size = new Size(width, height);
- var frameCount = stream.ReadUInt16();
+ var start = s.Position;
- var frames = new FrameHeader[frameCount];
- Frames = frames.AsReadOnly();
+ // First word is zero
+ if (s.ReadUInt16() != 0)
+ {
+ s.Position = start;
+ return false;
+ }
+
+ // Sanity Check the image count
+ s.Position += 4;
+ var imageCount = s.ReadUInt16();
+ if (s.Position + 24 * imageCount > s.Length)
+ {
+ s.Position = start;
+ return false;
+ }
+
+ // Check the size and format flag
+ // Some files define bogus frames, so loop until we find a valid one
+ s.Position += 4;
+ ushort w, h, f = 0;
+ byte type;
+ do
+ {
+ w = s.ReadUInt16();
+ h = s.ReadUInt16();
+ type = s.ReadUInt8();
+ }
+ while (w == 0 && h == 0 && f++ < imageCount);
+
+ s.Position = start;
+ return type < 4;
+ }
+
+ ShpTSFrame[] ParseFrames(Stream s)
+ {
+ var start = s.Position;
+
+ s.ReadUInt16();
+ var width = s.ReadUInt16();
+ var height = s.ReadUInt16();
+ var size = new Size(width, height);
+ var frameCount = s.ReadUInt16();
+
+ var frames = new ShpTSFrame[frameCount];
for (var i = 0; i < frames.Length; i++)
- frames[i] = new FrameHeader(stream, size);
+ frames[i] = new ShpTSFrame(s, size);
for (var i = 0; i < frameCount; i++)
{
@@ -66,13 +106,13 @@ namespace OpenRA.FileFormats
if (f.FileOffset == 0)
continue;
- stream.Position = f.FileOffset;
+ s.Position = f.FileOffset;
var frameSize = f.Size.Width * f.Size.Height;
// Uncompressed
if (f.Format == 1 || f.Format == 0)
- f.Data = stream.ReadBytes(frameSize);
+ f.Data = s.ReadBytes(frameSize);
// Uncompressed scanlines
else if (f.Format == 2)
@@ -80,9 +120,9 @@ namespace OpenRA.FileFormats
f.Data = new byte[frameSize];
for (var j = 0; j < f.Size.Height; j++)
{
- var length = stream.ReadUInt16() - 2;
+ var length = s.ReadUInt16() - 2;
var offset = f.Size.Width * j;
- stream.ReadBytes(f.Data, offset, length);
+ s.ReadBytes(f.Data, offset, length);
}
}
@@ -92,12 +132,27 @@ namespace OpenRA.FileFormats
f.Data = new byte[frameSize];
for (var j = 0; j < f.Size.Height; j++)
{
- var length = stream.ReadUInt16() - 2;
+ var length = s.ReadUInt16() - 2;
var offset = f.Size.Width * j;
- Format2.DecodeInto(stream.ReadBytes(length), f.Data, offset);
+ Format2.DecodeInto(s.ReadBytes(length), f.Data, offset);
}
}
}
+
+ s.Position = start;
+ return frames;
+ }
+
+ public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
+ {
+ if (!IsShpTS(s))
+ {
+ frames = null;
+ return false;
+ }
+
+ frames = ParseFrames(s);
+ return true;
}
}
-}
\ No newline at end of file
+}
diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml
index a7e412249e..2bffd79982 100644
--- a/mods/cnc/mod.yaml
+++ b/mods/cnc/mod.yaml
@@ -211,4 +211,4 @@ Missions:
SupportsMapsFrom: cnc
-SpriteFormats: ShpTD
\ No newline at end of file
+SpriteFormats: ShpTD, ShpTS
\ No newline at end of file
diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml
index 2807d787b6..24882a5e1c 100644
--- a/mods/ra/mod.yaml
+++ b/mods/ra/mod.yaml
@@ -208,4 +208,4 @@ Missions:
SupportsMapsFrom: ra
-SpriteFormats: ShpTD
\ No newline at end of file
+SpriteFormats: ShpTD, ShpTS
\ No newline at end of file
diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml
index 28fcce5127..ce7a0b001e 100644
--- a/mods/ts/mod.yaml
+++ b/mods/ts/mod.yaml
@@ -230,4 +230,4 @@ LuaScripts:
SupportsMapsFrom: ts
-SpriteFormats: ShpTD
\ No newline at end of file
+SpriteFormats: ShpTD, ShpTS
\ No newline at end of file