Merge pull request #6673 from pchote/unhardcode-sprites
Move sprite parsers into mod code
This commit is contained in:
2
Makefile
2
Makefile
@@ -166,7 +166,7 @@ mod_ts: $(mod_ts_TARGET)
|
|||||||
editor_SRCS := $(shell find OpenRA.Editor/ -iname '*.cs')
|
editor_SRCS := $(shell find OpenRA.Editor/ -iname '*.cs')
|
||||||
editor_TARGET = OpenRA.Editor.exe
|
editor_TARGET = OpenRA.Editor.exe
|
||||||
editor_KIND = winexe
|
editor_KIND = winexe
|
||||||
editor_DEPS = $(game_TARGET)
|
editor_DEPS = $(game_TARGET) $(mod_common_TARGET)
|
||||||
editor_LIBS = System.Windows.Forms.dll System.Data.dll System.Drawing.dll $(editor_DEPS) thirdparty/Eluant.dll
|
editor_LIBS = System.Windows.Forms.dll System.Data.dll System.Drawing.dll $(editor_DEPS) thirdparty/Eluant.dll
|
||||||
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
editor_EXTRA = -resource:OpenRA.Editor.Form1.resources -resource:OpenRA.Editor.MapSelect.resources
|
||||||
editor_FLAGS = -win32icon:OpenRA.Editor/OpenRA.Editor.Icon.ico
|
editor_FLAGS = -win32icon:OpenRA.Editor/OpenRA.Editor.Icon.ico
|
||||||
|
|||||||
@@ -160,6 +160,10 @@
|
|||||||
<Project>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</Project>
|
<Project>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</Project>
|
||||||
<Name>OpenRA.Game</Name>
|
<Name>OpenRA.Game</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\OpenRA.Mods.Common\OpenRA.Mods.Common.csproj">
|
||||||
|
<Project>{FE6C8CC0-2F07-442A-B29F-17617B3B7FC6}</Project>
|
||||||
|
<Name>OpenRA.Mods.Common</Name>
|
||||||
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="OpenRA.Editor.Icon.ico" />
|
<Content Include="OpenRA.Editor.Icon.ico" />
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ using System.Linq;
|
|||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
using OpenRA.Mods.Common.SpriteLoaders;
|
||||||
using OpenRA.Traits;
|
using OpenRA.Traits;
|
||||||
|
|
||||||
namespace OpenRA.Editor
|
namespace OpenRA.Editor
|
||||||
{
|
{
|
||||||
static class RenderUtils
|
static class RenderUtils
|
||||||
{
|
{
|
||||||
static Bitmap RenderShp(ISpriteSource shp, IPalette p)
|
static Bitmap RenderShp(ShpTDSprite shp, IPalette p)
|
||||||
{
|
{
|
||||||
var frame = shp.Frames.First();
|
var frame = shp.Frames.First();
|
||||||
|
|
||||||
@@ -50,14 +51,14 @@ namespace OpenRA.Editor
|
|||||||
var image = info.Traits.Get<ILegacyEditorRenderInfo>().EditorImage(info);
|
var image = info.Traits.Get<ILegacyEditorRenderInfo>().EditorImage(info);
|
||||||
using (var s = GlobalFileSystem.OpenWithExts(image, tileset.Extensions))
|
using (var s = GlobalFileSystem.OpenWithExts(image, tileset.Extensions))
|
||||||
{
|
{
|
||||||
var shp = new ShpReader(s);
|
var shp = new ShpTDSprite(s);
|
||||||
var bitmap = RenderShp(shp, p);
|
var bitmap = RenderShp(shp, p);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var s2 = GlobalFileSystem.OpenWithExts(image + "2", tileset.Extensions))
|
using (var s2 = GlobalFileSystem.OpenWithExts(image + "2", tileset.Extensions))
|
||||||
{
|
{
|
||||||
var shp2 = new ShpReader(s2);
|
var shp2 = new ShpTDSprite(s2);
|
||||||
var roofBitmap = RenderShp(shp2, p);
|
var roofBitmap = RenderShp(shp2, p);
|
||||||
|
|
||||||
using (var g = System.Drawing.Graphics.FromImage(bitmap))
|
using (var g = System.Drawing.Graphics.FromImage(bitmap))
|
||||||
@@ -81,7 +82,7 @@ namespace OpenRA.Editor
|
|||||||
using (var s = GlobalFileSystem.OpenWithExts(image, exts))
|
using (var s = GlobalFileSystem.OpenWithExts(image, exts))
|
||||||
{
|
{
|
||||||
// TODO: Do this properly
|
// TODO: Do this properly
|
||||||
var shp = new ShpReader(s) as ISpriteSource;
|
var shp = new ShpTDSprite(s);
|
||||||
var frame = shp.Frames.Last();
|
var frame = shp.Frames.Last();
|
||||||
|
|
||||||
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
|
||||||
|
|||||||
@@ -271,18 +271,19 @@ namespace OpenRA.Editor
|
|||||||
for (var i = 0; i < ChunkSize; i++)
|
for (var i = 0; i < ChunkSize; i++)
|
||||||
for (var j = 0; j < ChunkSize; j++)
|
for (var j = 0; j < ChunkSize; j++)
|
||||||
{
|
{
|
||||||
var cell = new CPos(u * ChunkSize + i, v * ChunkSize + j);
|
var ui = u * ChunkSize + i;
|
||||||
var tr = Map.MapTiles.Value[cell];
|
var vj = v * ChunkSize + j;
|
||||||
|
var tr = Map.MapTiles.Value[ui, vj];
|
||||||
var tile = TileSetRenderer.Data(tr.Type);
|
var tile = TileSetRenderer.Data(tr.Type);
|
||||||
var index = (tr.Index < tile.Count) ? tr.Index : (byte)0;
|
var index = (tr.Index < tile.Length) ? tr.Index : (byte)0;
|
||||||
var rawImage = tile[index];
|
var rawImage = tile[index];
|
||||||
for (var x = 0; x < TileSetRenderer.TileSize; x++)
|
for (var x = 0; x < TileSetRenderer.TileSize; x++)
|
||||||
for (var y = 0; y < TileSetRenderer.TileSize; y++)
|
for (var y = 0; y < TileSetRenderer.TileSize; y++)
|
||||||
p[(j * TileSetRenderer.TileSize + y) * stride + i * TileSetRenderer.TileSize + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize * y]).ToArgb();
|
p[(j * TileSetRenderer.TileSize + y) * stride + i * TileSetRenderer.TileSize + x] = Palette.GetColor(rawImage[x + TileSetRenderer.TileSize * y]).ToArgb();
|
||||||
|
|
||||||
if (Map.MapResources.Value[cell].Type != 0)
|
if (Map.MapResources.Value[ui, vj].Type != 0)
|
||||||
{
|
{
|
||||||
var resourceImage = ResourceTemplates[Map.MapResources.Value[cell].Type].Bitmap;
|
var resourceImage = ResourceTemplates[Map.MapResources.Value[ui, vj].Type].Bitmap;
|
||||||
var srcdata = resourceImage.LockBits(resourceImage.Bounds(),
|
var srcdata = resourceImage.LockBits(resourceImage.Bounds(),
|
||||||
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace OpenRA.Editor
|
|||||||
{
|
{
|
||||||
public readonly int TileSize;
|
public readonly int TileSize;
|
||||||
public TileSet TileSet;
|
public TileSet TileSet;
|
||||||
Dictionary<ushort, List<byte[]>> templates;
|
Dictionary<ushort, byte[][]> templates;
|
||||||
|
|
||||||
// Extract a square tile that the editor can render
|
// Extract a square tile that the editor can render
|
||||||
byte[] ExtractSquareTile(ISpriteFrame frame)
|
byte[] ExtractSquareTile(ISpriteFrame frame)
|
||||||
@@ -44,42 +44,19 @@ namespace OpenRA.Editor
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<byte[]> LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
|
|
||||||
{
|
|
||||||
ISpriteSource source;
|
|
||||||
if (!sourceCache.ContainsKey(filename))
|
|
||||||
{
|
|
||||||
using (var s = GlobalFileSystem.OpenWithExts(filename, exts))
|
|
||||||
source = SpriteSource.LoadSpriteSource(s, filename);
|
|
||||||
|
|
||||||
if (source.CacheWhenLoadingTileset)
|
|
||||||
sourceCache.Add(filename, source);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
source = sourceCache[filename];
|
|
||||||
|
|
||||||
if (frames != null)
|
|
||||||
{
|
|
||||||
var ret = new List<byte[]>();
|
|
||||||
var srcFrames = source.Frames;
|
|
||||||
foreach (var i in frames)
|
|
||||||
ret.Add(ExtractSquareTile(srcFrames[i]));
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
return source.Frames.Select(f => ExtractSquareTile(f)).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
public TileSetRenderer(TileSet tileset, Size tileSize)
|
public TileSetRenderer(TileSet tileset, Size tileSize)
|
||||||
{
|
{
|
||||||
this.TileSet = tileset;
|
this.TileSet = tileset;
|
||||||
this.TileSize = Math.Min(tileSize.Width, tileSize.Height);
|
this.TileSize = Math.Min(tileSize.Width, tileSize.Height);
|
||||||
|
|
||||||
templates = new Dictionary<ushort, List<byte[]>>();
|
templates = new Dictionary<ushort, byte[][]>();
|
||||||
var sourceCache = new Dictionary<string, ISpriteSource>();
|
var spriteLoader = new SpriteLoader(Game.modData.SpriteLoaders, tileset.Extensions, null);
|
||||||
foreach (var t in TileSet.Templates)
|
foreach (var t in tileset.Templates)
|
||||||
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
|
{
|
||||||
|
var allFrames = spriteLoader.LoadAllFrames(t.Value.Image);
|
||||||
|
var frames = t.Value.Frames != null ? t.Value.Frames.Select(f => allFrames[f]).ToArray() : allFrames;
|
||||||
|
templates.Add(t.Value.Id, frames.Select(f => ExtractSquareTile(f)).ToArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap RenderTemplate(ushort id, IPalette p)
|
public Bitmap RenderTemplate(ushort id, IPalette p)
|
||||||
@@ -125,7 +102,7 @@ namespace OpenRA.Editor
|
|||||||
return bitmap;
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<byte[]> Data(ushort id)
|
public byte[][] Data(ushort id)
|
||||||
{
|
{
|
||||||
return templates[id];
|
return templates[id];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2014 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using OpenRA.Graphics;
|
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
|
||||||
{
|
|
||||||
public class TmpRAReader : ISpriteSource
|
|
||||||
{
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
|
|
||||||
public TmpRAReader(Stream s)
|
|
||||||
{
|
|
||||||
var width = s.ReadUInt16();
|
|
||||||
var height = s.ReadUInt16();
|
|
||||||
var size = new Size(width, height);
|
|
||||||
|
|
||||||
s.Position += 12;
|
|
||||||
var imgStart = s.ReadUInt32();
|
|
||||||
s.Position += 8;
|
|
||||||
var indexEnd = s.ReadInt32();
|
|
||||||
s.Position += 4;
|
|
||||||
var indexStart = s.ReadInt32();
|
|
||||||
|
|
||||||
s.Position = indexStart;
|
|
||||||
var count = indexEnd - indexStart;
|
|
||||||
var tiles = new TmpTile[count];
|
|
||||||
Frames = tiles.AsReadOnly();
|
|
||||||
var tilesIndex = 0;
|
|
||||||
foreach (var b in s.ReadBytes(count))
|
|
||||||
{
|
|
||||||
if (b != 255)
|
|
||||||
{
|
|
||||||
s.Position = imgStart + b * width * height;
|
|
||||||
tiles[tilesIndex++] = new TmpTile(s.ReadBytes(width * height), size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tiles[tilesIndex++] = new TmpTile(null, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2014 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using OpenRA.Graphics;
|
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
|
||||||
{
|
|
||||||
public class TmpTile : ISpriteFrame
|
|
||||||
{
|
|
||||||
public Size Size { get; private set; }
|
|
||||||
public Size FrameSize { get; private set; }
|
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
|
||||||
public byte[] Data { get; set; }
|
|
||||||
|
|
||||||
public TmpTile(byte[] data, Size size)
|
|
||||||
{
|
|
||||||
FrameSize = size;
|
|
||||||
Data = data;
|
|
||||||
|
|
||||||
if (data == null)
|
|
||||||
Data = new byte[0];
|
|
||||||
else
|
|
||||||
Size = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TmpTDReader : ISpriteSource
|
|
||||||
{
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
|
|
||||||
public TmpTDReader(Stream s)
|
|
||||||
{
|
|
||||||
var width = s.ReadUInt16();
|
|
||||||
var height = s.ReadUInt16();
|
|
||||||
var size = new Size(width, height);
|
|
||||||
|
|
||||||
s.Position += 8;
|
|
||||||
var imgStart = s.ReadUInt32();
|
|
||||||
s.Position += 8;
|
|
||||||
var indexEnd = s.ReadInt32();
|
|
||||||
var indexStart = s.ReadInt32();
|
|
||||||
|
|
||||||
s.Position = indexStart;
|
|
||||||
var count = indexEnd - indexStart;
|
|
||||||
var tiles = new TmpTile[count];
|
|
||||||
Frames = tiles.AsReadOnly();
|
|
||||||
var tilesIndex = 0;
|
|
||||||
foreach (var b in s.ReadBytes(count))
|
|
||||||
{
|
|
||||||
if (b != 255)
|
|
||||||
{
|
|
||||||
s.Position = imgStart + b * width * height;
|
|
||||||
tiles[tilesIndex++] = new TmpTile(s.ReadBytes(width * height), size);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
tiles[tilesIndex++] = new TmpTile(null, size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2014 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using OpenRA.Graphics;
|
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
|
||||||
{
|
|
||||||
public class TmpTSTile : ISpriteFrame
|
|
||||||
{
|
|
||||||
public Size Size { get; private set; }
|
|
||||||
public Size FrameSize { get { return Size; } }
|
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
|
||||||
public byte[] Data { get; set; }
|
|
||||||
|
|
||||||
public TmpTSTile(Stream s, Size size)
|
|
||||||
{
|
|
||||||
Size = size;
|
|
||||||
|
|
||||||
// Ignore tile header for now
|
|
||||||
s.Position += 52;
|
|
||||||
|
|
||||||
Data = new byte[size.Width * size.Height];
|
|
||||||
|
|
||||||
// Unpack tile data
|
|
||||||
var width = 4;
|
|
||||||
for (var i = 0; i < size.Height; i++)
|
|
||||||
{
|
|
||||||
var start = i * size.Width + (size.Width - width) / 2;
|
|
||||||
for (var j = 0; j < width; j++)
|
|
||||||
Data[start + j] = s.ReadUInt8();
|
|
||||||
|
|
||||||
width += (i < size.Height / 2 - 1 ? 1 : -1) * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ignore Z-data for now
|
|
||||||
// Ignore extra data for now
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TmpTSReader : ISpriteSource
|
|
||||||
{
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
|
|
||||||
public TmpTSReader(Stream s)
|
|
||||||
{
|
|
||||||
var templateWidth = s.ReadUInt32();
|
|
||||||
var templateHeight = s.ReadUInt32();
|
|
||||||
var tileWidth = s.ReadInt32();
|
|
||||||
var tileHeight = s.ReadInt32();
|
|
||||||
var size = new Size(tileWidth, tileHeight);
|
|
||||||
var offsets = new uint[templateWidth * templateHeight];
|
|
||||||
for (var i = 0; i < offsets.Length; i++)
|
|
||||||
offsets[i] = s.ReadUInt32();
|
|
||||||
|
|
||||||
var tiles = new List<TmpTSTile>();
|
|
||||||
for (var i = 0; i < offsets.Length; i++)
|
|
||||||
{
|
|
||||||
s.Position = offsets[i];
|
|
||||||
tiles.Add(new TmpTSTile(s, size));
|
|
||||||
}
|
|
||||||
|
|
||||||
Frames = tiles.ToArray().AsReadOnly();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ namespace OpenRA.Graphics
|
|||||||
foreach (var p in nodesDict["Palettes"].Nodes)
|
foreach (var p in nodesDict["Palettes"].Nodes)
|
||||||
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
|
palette.AddPalette(p.Key, new ImmutablePalette(GlobalFileSystem.Open(p.Value.Value), shadowIndex), false);
|
||||||
|
|
||||||
var spriteLoader = new SpriteLoader(new string[0], new SheetBuilder(SheetType.Indexed));
|
var spriteLoader = new SpriteLoader(modData.SpriteLoaders, new string[0], new SheetBuilder(SheetType.Indexed));
|
||||||
foreach (var s in nodesDict["Cursors"].Nodes)
|
foreach (var s in nodesDict["Cursors"].Nodes)
|
||||||
LoadSequencesForCursor(spriteLoader, s.Key, s.Value);
|
LoadSequencesForCursor(spriteLoader, s.Key, s.Value);
|
||||||
spriteLoader.SheetBuilder.Current.ReleaseBuffer();
|
spriteLoader.SheetBuilder.Current.ReleaseBuffer();
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ namespace OpenRA.Graphics
|
|||||||
{
|
{
|
||||||
this.modData = modData;
|
this.modData = modData;
|
||||||
|
|
||||||
spriteLoader = Exts.Lazy(() => new SpriteLoader(tileSet.Extensions, new SheetBuilder(SheetType.Indexed)));
|
spriteLoader = Exts.Lazy(() => new SpriteLoader(modData.SpriteLoaders, tileSet.Extensions, new SheetBuilder(SheetType.Indexed)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Sequences LoadSequences(Map map)
|
public Sequences LoadSequences(Map map)
|
||||||
|
|||||||
@@ -8,35 +8,67 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
using OpenRA.Primitives;
|
using OpenRA.Primitives;
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
namespace OpenRA.Graphics
|
||||||
{
|
{
|
||||||
|
public interface ISpriteLoader
|
||||||
|
{
|
||||||
|
bool TryParseSprite(Stream s, out ISpriteFrame[] frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ISpriteFrame
|
||||||
|
{
|
||||||
|
Size Size { get; }
|
||||||
|
Size FrameSize { get; }
|
||||||
|
float2 Offset { get; }
|
||||||
|
byte[] Data { get; }
|
||||||
|
bool DisableExportPadding { get; }
|
||||||
|
}
|
||||||
|
|
||||||
public class SpriteLoader
|
public class SpriteLoader
|
||||||
{
|
{
|
||||||
public readonly SheetBuilder SheetBuilder;
|
public readonly SheetBuilder SheetBuilder;
|
||||||
|
readonly ISpriteLoader[] loaders;
|
||||||
readonly Cache<string, Sprite[]> sprites;
|
readonly Cache<string, Sprite[]> sprites;
|
||||||
|
readonly Cache<string, ISpriteFrame[]> frames;
|
||||||
readonly string[] exts;
|
readonly string[] exts;
|
||||||
|
|
||||||
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
|
public SpriteLoader(ISpriteLoader[] loaders, string[] exts, SheetBuilder sheetBuilder)
|
||||||
{
|
{
|
||||||
|
this.loaders = loaders;
|
||||||
SheetBuilder = sheetBuilder;
|
SheetBuilder = sheetBuilder;
|
||||||
|
|
||||||
// Include extension-less version
|
// Include extension-less version
|
||||||
this.exts = exts.Append("").ToArray();
|
this.exts = exts.Append("").ToArray();
|
||||||
sprites = new Cache<string, Sprite[]>(CacheSpriteFrames);
|
sprites = new Cache<string, Sprite[]>(CacheSprites);
|
||||||
|
frames = new Cache<string, ISpriteFrame[]>(CacheFrames);
|
||||||
}
|
}
|
||||||
|
|
||||||
Sprite[] CacheSpriteFrames(string filename)
|
Sprite[] CacheSprites(string filename)
|
||||||
{
|
{
|
||||||
using (var stream = GlobalFileSystem.OpenWithExts(filename, exts))
|
return frames[filename].Select(a => SheetBuilder.Add(a))
|
||||||
return SpriteSource.LoadSpriteSource(stream, filename).Frames
|
|
||||||
.Select(a => SheetBuilder.Add(a))
|
|
||||||
.ToArray();
|
.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ISpriteFrame[] CacheFrames(string filename)
|
||||||
|
{
|
||||||
|
using (var stream = GlobalFileSystem.OpenWithExts(filename, exts))
|
||||||
|
{
|
||||||
|
ISpriteFrame[] frames;
|
||||||
|
foreach (var loader in loaders)
|
||||||
|
if (loader.TryParseSprite(stream, out frames))
|
||||||
|
return frames;
|
||||||
|
|
||||||
|
throw new InvalidDataException(filename + " is not a valid sprite file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }
|
||||||
|
public ISpriteFrame[] LoadAllFrames(string filename) { return frames[filename]; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,264 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2014 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using OpenRA.FileFormats;
|
|
||||||
|
|
||||||
namespace OpenRA.Graphics
|
|
||||||
{
|
|
||||||
public interface ISpriteFrame
|
|
||||||
{
|
|
||||||
Size Size { get; }
|
|
||||||
Size FrameSize { get; }
|
|
||||||
float2 Offset { get; }
|
|
||||||
byte[] Data { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface ISpriteSource
|
|
||||||
{
|
|
||||||
IReadOnlyList<ISpriteFrame> Frames { get; }
|
|
||||||
bool CacheWhenLoadingTileset { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Most of this should be moved into the format parsers themselves.
|
|
||||||
public enum SpriteType { Unknown, ShpTD, ShpTS, ShpD2, TmpTD, TmpRA, TmpTS, R8 }
|
|
||||||
public static class SpriteSource
|
|
||||||
{
|
|
||||||
static bool IsTmpRA(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
|
|
||||||
s.Position += 20;
|
|
||||||
var a = s.ReadUInt32();
|
|
||||||
s.Position += 2;
|
|
||||||
var b = s.ReadUInt16();
|
|
||||||
|
|
||||||
s.Position = start;
|
|
||||||
return a == 0 && b == 0x2c73;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsTmpTD(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
|
|
||||||
s.Position += 16;
|
|
||||||
var a = s.ReadUInt32();
|
|
||||||
var b = s.ReadUInt32();
|
|
||||||
|
|
||||||
s.Position = start;
|
|
||||||
return a == 0 && b == 0x0D1AFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsTmpTS(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
s.Position += 8;
|
|
||||||
var sx = s.ReadUInt32();
|
|
||||||
var sy = s.ReadUInt32();
|
|
||||||
|
|
||||||
// Find the first frame
|
|
||||||
var offset = s.ReadUInt32();
|
|
||||||
|
|
||||||
if (offset > s.Length - 52)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Position = offset + 12;
|
|
||||||
var test = s.ReadUInt32();
|
|
||||||
|
|
||||||
s.Position = start;
|
|
||||||
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 IsShpTD(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
|
|
||||||
// First word is the image count
|
|
||||||
var imageCount = s.ReadUInt16();
|
|
||||||
if (imageCount == 0)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Last offset should point to the end of file
|
|
||||||
var finalOffset = start + 14 + 8 * imageCount;
|
|
||||||
if (finalOffset > s.Length)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Position = finalOffset;
|
|
||||||
var eof = s.ReadUInt32();
|
|
||||||
if (eof != s.Length)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the format flag on the first frame
|
|
||||||
s.Position = start + 17;
|
|
||||||
var b = s.ReadUInt8();
|
|
||||||
|
|
||||||
s.Position = start;
|
|
||||||
return b == 0x20 || b == 0x40 || b == 0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsShpD2(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
|
|
||||||
// First word is the image count
|
|
||||||
var imageCount = s.ReadUInt16();
|
|
||||||
if (imageCount == 0)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test for two vs four byte offset
|
|
||||||
var testOffset = s.ReadUInt32();
|
|
||||||
var offsetSize = (testOffset & 0xFF0000) > 0 ? 2 : 4;
|
|
||||||
|
|
||||||
// Last offset should point to the end of file
|
|
||||||
var finalOffset = start + 2 + offsetSize * imageCount;
|
|
||||||
if (finalOffset > s.Length)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
s.Position = finalOffset;
|
|
||||||
var eof = offsetSize == 2 ? s.ReadUInt16() : s.ReadUInt32();
|
|
||||||
if (eof + 2 != s.Length)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the format flag on the first frame
|
|
||||||
var b = s.ReadUInt16();
|
|
||||||
s.Position = start;
|
|
||||||
return b == 5 || b <= 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool IsR8(Stream s)
|
|
||||||
{
|
|
||||||
var start = s.Position;
|
|
||||||
|
|
||||||
// First byte is nonzero
|
|
||||||
if (s.ReadUInt8() == 0)
|
|
||||||
{
|
|
||||||
s.Position = start;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check the format of the first frame
|
|
||||||
s.Position = start + 25;
|
|
||||||
var d = s.ReadUInt8();
|
|
||||||
|
|
||||||
s.Position = start;
|
|
||||||
return d == 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static SpriteType DetectSpriteType(Stream s)
|
|
||||||
{
|
|
||||||
if (IsShpTD(s))
|
|
||||||
return SpriteType.ShpTD;
|
|
||||||
|
|
||||||
if (IsShpTS(s))
|
|
||||||
return SpriteType.ShpTS;
|
|
||||||
|
|
||||||
if (IsR8(s))
|
|
||||||
return SpriteType.R8;
|
|
||||||
|
|
||||||
if (IsTmpRA(s))
|
|
||||||
return SpriteType.TmpRA;
|
|
||||||
|
|
||||||
if (IsTmpTD(s))
|
|
||||||
return SpriteType.TmpTD;
|
|
||||||
|
|
||||||
if (IsTmpTS(s))
|
|
||||||
return SpriteType.TmpTS;
|
|
||||||
|
|
||||||
if (IsShpD2(s))
|
|
||||||
return SpriteType.ShpD2;
|
|
||||||
|
|
||||||
return SpriteType.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISpriteSource LoadSpriteSource(Stream s, string filename)
|
|
||||||
{
|
|
||||||
var type = DetectSpriteType(s);
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case SpriteType.ShpTD:
|
|
||||||
return new ShpReader(s);
|
|
||||||
case SpriteType.ShpTS:
|
|
||||||
return new ShpTSReader(s);
|
|
||||||
case SpriteType.R8:
|
|
||||||
return new R8Reader(s);
|
|
||||||
case SpriteType.TmpRA:
|
|
||||||
return new TmpRAReader(s);
|
|
||||||
case SpriteType.TmpTD:
|
|
||||||
return new TmpTDReader(s);
|
|
||||||
case SpriteType.TmpTS:
|
|
||||||
return new TmpTSReader(s);
|
|
||||||
case SpriteType.ShpD2:
|
|
||||||
return new ShpD2Reader(s);
|
|
||||||
case SpriteType.Unknown:
|
|
||||||
default:
|
|
||||||
throw new InvalidDataException(filename + " is not a valid sprite file");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -22,33 +22,6 @@ namespace OpenRA.Graphics
|
|||||||
Dictionary<ushort, Sprite[]> templates;
|
Dictionary<ushort, Sprite[]> templates;
|
||||||
Sprite missingTile;
|
Sprite missingTile;
|
||||||
|
|
||||||
Sprite[] LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
|
|
||||||
{
|
|
||||||
ISpriteSource source;
|
|
||||||
if (!sourceCache.ContainsKey(filename))
|
|
||||||
{
|
|
||||||
using (var s = GlobalFileSystem.OpenWithExts(filename, exts))
|
|
||||||
source = SpriteSource.LoadSpriteSource(s, filename);
|
|
||||||
|
|
||||||
if (source.CacheWhenLoadingTileset)
|
|
||||||
sourceCache.Add(filename, source);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
source = sourceCache[filename];
|
|
||||||
|
|
||||||
if (frames != null)
|
|
||||||
{
|
|
||||||
var ret = new List<Sprite>();
|
|
||||||
var srcFrames = source.Frames.ToArray();
|
|
||||||
foreach (var i in frames)
|
|
||||||
ret.Add(sheetBuilder.Add(srcFrames[i]));
|
|
||||||
|
|
||||||
return ret.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
return source.Frames.Select(f => sheetBuilder.Add(f)).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Theater(TileSet tileset)
|
public Theater(TileSet tileset)
|
||||||
{
|
{
|
||||||
var allocated = false;
|
var allocated = false;
|
||||||
@@ -61,11 +34,17 @@ namespace OpenRA.Graphics
|
|||||||
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize), true);
|
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize), true);
|
||||||
};
|
};
|
||||||
|
|
||||||
var sourceCache = new Dictionary<string, ISpriteSource>();
|
|
||||||
templates = new Dictionary<ushort, Sprite[]>();
|
|
||||||
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
|
||||||
|
templates = new Dictionary<ushort, Sprite[]>();
|
||||||
|
|
||||||
|
// We manage the SheetBuilder ourselves, to avoid loading all of the tileset images
|
||||||
|
var spriteLoader = new SpriteLoader(Game.modData.SpriteLoaders, tileset.Extensions, null);
|
||||||
foreach (var t in tileset.Templates)
|
foreach (var t in tileset.Templates)
|
||||||
templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
|
{
|
||||||
|
var allFrames = spriteLoader.LoadAllFrames(t.Value.Image);
|
||||||
|
var frames = t.Value.Frames != null ? t.Value.Frames.Select(f => allFrames[f]).ToArray() : allFrames;
|
||||||
|
templates.Add(t.Value.Id, frames.Select(f => sheetBuilder.Add(f)).ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
// 1x1px transparent tile
|
// 1x1px transparent tile
|
||||||
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
|
missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1));
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ namespace OpenRA
|
|||||||
public readonly Size TileSize = new Size(24, 24);
|
public readonly Size TileSize = new Size(24, 24);
|
||||||
public readonly TileShape TileShape = TileShape.Rectangle;
|
public readonly TileShape TileShape = TileShape.Rectangle;
|
||||||
|
|
||||||
|
public readonly string[] SpriteFormats = { };
|
||||||
|
|
||||||
[Desc("(x,y,z) offset of the full cell and each sub-cell", "X & Y should be between -512 ... 512 and Z >= 0")]
|
[Desc("(x,y,z) offset of the full cell and each sub-cell", "X & Y should be between -512 ... 512 and Z >= 0")]
|
||||||
public readonly WVec[] SubCellOffsets =
|
public readonly WVec[] SubCellOffsets =
|
||||||
{
|
{
|
||||||
@@ -128,6 +130,9 @@ namespace OpenRA
|
|||||||
compat.Add(c.Trim());
|
compat.Add(c.Trim());
|
||||||
|
|
||||||
MapCompatibility = compat.ToArray();
|
MapCompatibility = compat.ToArray();
|
||||||
|
|
||||||
|
if (yaml.ContainsKey("SpriteFormats"))
|
||||||
|
SpriteFormats = FieldLoader.GetValue<string[]>("SpriteFormats", yaml["SpriteFormats"].Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key)
|
static string[] YamlList(Dictionary<string, MiniYaml> yaml, string key)
|
||||||
|
|||||||
@@ -457,7 +457,7 @@ namespace OpenRA
|
|||||||
for (var i = 0; i < MapSize.X; i++)
|
for (var i = 0; i < MapSize.X; i++)
|
||||||
for (var j = 0; j < MapSize.Y; j++)
|
for (var j = 0; j < MapSize.Y; j++)
|
||||||
{
|
{
|
||||||
var tile = MapTiles.Value[new CPos(i, j)];
|
var tile = MapTiles.Value[i, j];
|
||||||
writer.Write(tile.Type);
|
writer.Write(tile.Type);
|
||||||
writer.Write(tile.Index);
|
writer.Write(tile.Index);
|
||||||
}
|
}
|
||||||
@@ -467,7 +467,7 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
for (var j = 0; j < MapSize.Y; j++)
|
for (var j = 0; j < MapSize.Y; j++)
|
||||||
{
|
{
|
||||||
var tile = MapResources.Value[new CPos(i, j)];
|
var tile = MapResources.Value[i, j];
|
||||||
writer.Write(tile.Type);
|
writer.Write(tile.Type);
|
||||||
writer.Write(tile.Index);
|
writer.Write(tile.Index);
|
||||||
}
|
}
|
||||||
@@ -654,9 +654,8 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
for (var i = Bounds.Left; i < Bounds.Right; i++)
|
for (var i = Bounds.Left; i < Bounds.Right; i++)
|
||||||
{
|
{
|
||||||
var cell = new CPos(i, j);
|
var type = MapTiles.Value[i, j].Type;
|
||||||
var type = MapTiles.Value[cell].Type;
|
var index = MapTiles.Value[i, j].Index;
|
||||||
var index = MapTiles.Value[cell].Index;
|
|
||||||
if (!tileset.Templates.ContainsKey(type))
|
if (!tileset.Templates.ContainsKey(type))
|
||||||
{
|
{
|
||||||
Console.WriteLine("Unknown Tile ID {0}".F(type));
|
Console.WriteLine("Unknown Tile ID {0}".F(type));
|
||||||
@@ -668,7 +667,7 @@ namespace OpenRA
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
index = (byte)r.Next(0, template.TilesCount);
|
index = (byte)r.Next(0, template.TilesCount);
|
||||||
MapTiles.Value[cell] = new TerrainTile(type, index);
|
MapTiles.Value[i, j] = new TerrainTile(type, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -730,7 +729,7 @@ namespace OpenRA
|
|||||||
for (var j = -max; j <= max; j++)
|
for (var j = -max; j <= max; j++)
|
||||||
for (var i = -max; i <= max; i++)
|
for (var i = -max; i <= max; i++)
|
||||||
if (max * max >= i * i + j * j)
|
if (max * max >= i * i + j * j)
|
||||||
ts [Exts.ISqrt(i * i + j * j, Exts.ISqrtRoundMode.Ceiling)].Add(new CVec(i, j));
|
ts[Exts.ISqrt(i * i + j * j, Exts.ISqrtRoundMode.Ceiling)].Add(new CVec(i, j));
|
||||||
|
|
||||||
// Sort each integer-distance group by the actual distance
|
// Sort each integer-distance group by the actual distance
|
||||||
foreach (var list in ts)
|
foreach (var list in ts)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ namespace OpenRA
|
|||||||
public readonly ObjectCreator ObjectCreator;
|
public readonly ObjectCreator ObjectCreator;
|
||||||
public readonly WidgetLoader WidgetLoader;
|
public readonly WidgetLoader WidgetLoader;
|
||||||
public readonly MapCache MapCache;
|
public readonly MapCache MapCache;
|
||||||
|
public readonly ISpriteLoader[] SpriteLoaders;
|
||||||
public ILoadScreen LoadScreen = null;
|
public ILoadScreen LoadScreen = null;
|
||||||
public VoxelLoader VoxelLoader;
|
public VoxelLoader VoxelLoader;
|
||||||
public readonly RulesetCache RulesetCache;
|
public readonly RulesetCache RulesetCache;
|
||||||
@@ -45,6 +46,18 @@ namespace OpenRA
|
|||||||
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
RulesetCache.LoadingProgress += HandleLoadingProgress;
|
||||||
MapCache = new MapCache(this);
|
MapCache = new MapCache(this);
|
||||||
|
|
||||||
|
var loaders = new List<ISpriteLoader>();
|
||||||
|
foreach (var format in Manifest.SpriteFormats)
|
||||||
|
{
|
||||||
|
var loader = ObjectCreator.FindType(format + "Loader");
|
||||||
|
if (loader == null || !loader.GetInterfaces().Contains(typeof(ISpriteLoader)))
|
||||||
|
throw new InvalidOperationException("Unable to find a sprite loader for type '{0}'.".F(format));
|
||||||
|
|
||||||
|
loaders.Add((ISpriteLoader)ObjectCreator.CreateBasic(loader));
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteLoaders = loaders.ToArray();
|
||||||
|
|
||||||
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
// HACK: Mount only local folders so we have a half-working environment for the asset installer
|
||||||
GlobalFileSystem.UnmountAll();
|
GlobalFileSystem.UnmountAll();
|
||||||
foreach (var dir in Manifest.Folders)
|
foreach (var dir in Manifest.Folders)
|
||||||
|
|||||||
@@ -277,13 +277,6 @@
|
|||||||
<Compile Include="FileFormats\XccLocalDatabase.cs" />
|
<Compile Include="FileFormats\XccLocalDatabase.cs" />
|
||||||
<Compile Include="FileFormats\HvaReader.cs" />
|
<Compile Include="FileFormats\HvaReader.cs" />
|
||||||
<Compile Include="FileFormats\PngLoader.cs" />
|
<Compile Include="FileFormats\PngLoader.cs" />
|
||||||
<Compile Include="FileFormats\R8Reader.cs" />
|
|
||||||
<Compile Include="FileFormats\ShpD2Reader.cs" />
|
|
||||||
<Compile Include="FileFormats\ShpReader.cs" />
|
|
||||||
<Compile Include="FileFormats\ShpTSReader.cs" />
|
|
||||||
<Compile Include="FileFormats\TmpRAReader.cs" />
|
|
||||||
<Compile Include="FileFormats\TmpTDReader.cs" />
|
|
||||||
<Compile Include="FileFormats\TmpTSReader.cs" />
|
|
||||||
<Compile Include="FileFormats\VqaReader.cs" />
|
<Compile Include="FileFormats\VqaReader.cs" />
|
||||||
<Compile Include="FileFormats\VxlReader.cs" />
|
<Compile Include="FileFormats\VxlReader.cs" />
|
||||||
<Compile Include="Primitives\ActionQueue.cs" />
|
<Compile Include="Primitives\ActionQueue.cs" />
|
||||||
@@ -320,7 +313,6 @@
|
|||||||
<Compile Include="Map\ActorReference.cs" />
|
<Compile Include="Map\ActorReference.cs" />
|
||||||
<Compile Include="Support\Evaluator.cs" />
|
<Compile Include="Support\Evaluator.cs" />
|
||||||
<Compile Include="Settings.cs" />
|
<Compile Include="Settings.cs" />
|
||||||
<Compile Include="Graphics\SpriteSource.cs" />
|
|
||||||
<Compile Include="Graphics\PlayerColorRemap.cs" />
|
<Compile Include="Graphics\PlayerColorRemap.cs" />
|
||||||
<Compile Include="Graphics\Palette.cs" />
|
<Compile Include="Graphics\Palette.cs" />
|
||||||
<Compile Include="FileSystem\GlobalFileSystem.cs" />
|
<Compile Include="FileSystem\GlobalFileSystem.cs" />
|
||||||
|
|||||||
@@ -87,7 +87,6 @@
|
|||||||
<Compile Include="UtilityCommands\ImportLegacyMapCommand.cs" />
|
<Compile Include="UtilityCommands\ImportLegacyMapCommand.cs" />
|
||||||
<Compile Include="UtilityCommands\LegacyMapImporter.cs" />
|
<Compile Include="UtilityCommands\LegacyMapImporter.cs" />
|
||||||
<Compile Include="UtilityCommands\RemapShpCommand.cs" />
|
<Compile Include="UtilityCommands\RemapShpCommand.cs" />
|
||||||
<Compile Include="UtilityCommands\TransposeShpCommand.cs" />
|
|
||||||
<Compile Include="UtilityCommands\UpgradeMapCommand.cs" />
|
<Compile Include="UtilityCommands\UpgradeMapCommand.cs" />
|
||||||
<Compile Include="UtilityCommands\UpgradeModCommand.cs" />
|
<Compile Include="UtilityCommands\UpgradeModCommand.cs" />
|
||||||
<Compile Include="UtilityCommands\UpgradeRules.cs" />
|
<Compile Include="UtilityCommands\UpgradeRules.cs" />
|
||||||
@@ -114,6 +113,11 @@
|
|||||||
<Compile Include="World\ResourceClaim.cs" />
|
<Compile Include="World\ResourceClaim.cs" />
|
||||||
<Compile Include="World\ResourceClaimLayer.cs" />
|
<Compile Include="World\ResourceClaimLayer.cs" />
|
||||||
<Compile Include="World\SmudgeLayer.cs" />
|
<Compile Include="World\SmudgeLayer.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\ShpTDLoader.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\ShpTSLoader.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\TmpRALoader.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\TmpTDLoader.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\ShpD2Loader.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -9,13 +9,16 @@
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.Mods.Common.SpriteLoaders
|
||||||
{
|
{
|
||||||
public class ShpD2Reader : ISpriteSource
|
public class ShpD2Loader : ISpriteLoader
|
||||||
{
|
{
|
||||||
[Flags] enum FormatFlags : int
|
[Flags] enum FormatFlags : int
|
||||||
{
|
{
|
||||||
@@ -24,14 +27,15 @@ namespace OpenRA.FileFormats
|
|||||||
VariableLengthTable = 4
|
VariableLengthTable = 4
|
||||||
}
|
}
|
||||||
|
|
||||||
class Frame : ISpriteFrame
|
class ShpD2Frame : ISpriteFrame
|
||||||
{
|
{
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get { return Size; } }
|
public Size FrameSize { get { return Size; } }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
public Frame(Stream s)
|
public ShpD2Frame(Stream s)
|
||||||
{
|
{
|
||||||
var flags = (FormatFlags)s.ReadUInt16();
|
var flags = (FormatFlags)s.ReadUInt16();
|
||||||
s.Position += 1;
|
s.Position += 1;
|
||||||
@@ -83,11 +87,48 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
bool IsShpD2(Stream s)
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
|
|
||||||
public ShpD2Reader(Stream s)
|
|
||||||
{
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
// First word is the image count
|
||||||
|
var imageCount = s.ReadUInt16();
|
||||||
|
if (imageCount == 0)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for two vs four byte offset
|
||||||
|
var testOffset = s.ReadUInt32();
|
||||||
|
var offsetSize = (testOffset & 0xFF0000) > 0 ? 2 : 4;
|
||||||
|
|
||||||
|
// Last offset should point to the end of file
|
||||||
|
var finalOffset = start + 2 + offsetSize * imageCount;
|
||||||
|
if (finalOffset > s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = finalOffset;
|
||||||
|
var eof = offsetSize == 2 ? s.ReadUInt16() : s.ReadUInt32();
|
||||||
|
if (eof + 2 != s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the format flag on the first frame
|
||||||
|
var b = s.ReadUInt16();
|
||||||
|
s.Position = start;
|
||||||
|
return b == 5 || b <= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShpD2Frame[] ParseFrames(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
var imageCount = s.ReadUInt16();
|
var imageCount = s.ReadUInt16();
|
||||||
|
|
||||||
// Last offset is pointer to end of file.
|
// Last offset is pointer to end of file.
|
||||||
@@ -101,13 +142,27 @@ namespace OpenRA.FileFormats
|
|||||||
for (var i = 0; i < imageCount + 1; i++)
|
for (var i = 0; i < imageCount + 1; i++)
|
||||||
offsets[i] = (twoByteOffset ? s.ReadUInt16() : s.ReadUInt32()) + 2;
|
offsets[i] = (twoByteOffset ? s.ReadUInt16() : s.ReadUInt32()) + 2;
|
||||||
|
|
||||||
var frames = new Frame[imageCount];
|
var frames = new ShpD2Frame[imageCount];
|
||||||
Frames = frames.AsReadOnly();
|
|
||||||
for (var i = 0; i < frames.Length; i++)
|
for (var i = 0; i < frames.Length; i++)
|
||||||
{
|
{
|
||||||
s.Position = offsets[i];
|
s.Position = offsets[i];
|
||||||
frames[i] = new Frame(s);
|
frames[i] = new ShpD2Frame(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsShpD2(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = ParseFrames(s);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,11 +13,63 @@ using System.Collections.Generic;
|
|||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.Mods.Common.SpriteLoaders
|
||||||
{
|
{
|
||||||
public class ShpReader : ISpriteSource
|
public class ShpTDLoader : ISpriteLoader
|
||||||
|
{
|
||||||
|
static bool IsShpTD(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
// First word is the image count
|
||||||
|
var imageCount = s.ReadUInt16();
|
||||||
|
if (imageCount == 0)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last offset should point to the end of file
|
||||||
|
var finalOffset = start + 14 + 8 * imageCount;
|
||||||
|
if (finalOffset > s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = finalOffset;
|
||||||
|
var eof = s.ReadUInt32();
|
||||||
|
if (eof != s.Length)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the format flag on the first frame
|
||||||
|
s.Position = start + 17;
|
||||||
|
var b = s.ReadUInt8();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return b == 0x20 || b == 0x40 || b == 0x80;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsShpTD(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = new ShpTDSprite(s).Frames.ToArray();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ShpTDSprite
|
||||||
{
|
{
|
||||||
enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
|
||||||
|
|
||||||
@@ -27,6 +79,7 @@ namespace OpenRA.FileFormats
|
|||||||
public Size FrameSize { get { return reader.Size; } }
|
public Size FrameSize { get { return reader.Size; } }
|
||||||
public float2 Offset { get { return float2.Zero; } }
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
public uint FileOffset;
|
public uint FileOffset;
|
||||||
public Format Format;
|
public Format Format;
|
||||||
@@ -35,12 +88,12 @@ namespace OpenRA.FileFormats
|
|||||||
public Format RefFormat;
|
public Format RefFormat;
|
||||||
public ImageHeader RefImage;
|
public ImageHeader RefImage;
|
||||||
|
|
||||||
ShpReader reader;
|
ShpTDSprite reader;
|
||||||
|
|
||||||
// Used by ShpWriter
|
// Used by ShpWriter
|
||||||
public ImageHeader() { }
|
public ImageHeader() { }
|
||||||
|
|
||||||
public ImageHeader(Stream stream, ShpReader reader)
|
public ImageHeader(Stream stream, ShpTDSprite reader)
|
||||||
{
|
{
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
var data = stream.ReadUInt32();
|
var data = stream.ReadUInt32();
|
||||||
@@ -60,7 +113,6 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
public readonly Size Size;
|
public readonly Size Size;
|
||||||
|
|
||||||
int recurseDepth = 0;
|
int recurseDepth = 0;
|
||||||
@@ -69,7 +121,7 @@ namespace OpenRA.FileFormats
|
|||||||
readonly long shpBytesFileOffset;
|
readonly long shpBytesFileOffset;
|
||||||
readonly byte[] shpBytes;
|
readonly byte[] shpBytes;
|
||||||
|
|
||||||
public ShpReader(Stream stream)
|
public ShpTDSprite(Stream stream)
|
||||||
{
|
{
|
||||||
imageCount = stream.ReadUInt16();
|
imageCount = stream.ReadUInt16();
|
||||||
stream.Position += 4;
|
stream.Position += 4;
|
||||||
@@ -149,12 +201,6 @@ namespace OpenRA.FileFormats
|
|||||||
return imageData;
|
return imageData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ShpReader Load(string filename)
|
|
||||||
{
|
|
||||||
using (var s = File.OpenRead(filename))
|
|
||||||
return new ShpReader(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Write(Stream s, Size size, IEnumerable<byte[]> frames)
|
public static void Write(Stream s, Size size, IEnumerable<byte[]> frames)
|
||||||
{
|
{
|
||||||
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
|
||||||
@@ -8,25 +8,30 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.Graphics;
|
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 Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get; private set; }
|
public float2 Offset { get; private set; }
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
public readonly uint FileOffset;
|
public readonly uint FileOffset;
|
||||||
public readonly byte Format;
|
public readonly byte Format;
|
||||||
|
|
||||||
public FrameHeader(Stream stream, Size frameSize)
|
public ShpTSFrame(Stream stream, Size frameSize)
|
||||||
{
|
{
|
||||||
var x = stream.ReadUInt16();
|
var x = stream.ReadUInt16();
|
||||||
var y = stream.ReadUInt16();
|
var y = stream.ReadUInt16();
|
||||||
@@ -44,21 +49,56 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
bool IsShpTS(Stream s)
|
||||||
public bool CacheWhenLoadingTileset { get { return false; } }
|
|
||||||
|
|
||||||
public ShpTSReader(Stream stream)
|
|
||||||
{
|
{
|
||||||
stream.ReadUInt16();
|
var start = s.Position;
|
||||||
var width = stream.ReadUInt16();
|
|
||||||
var height = stream.ReadUInt16();
|
|
||||||
var size = new Size(width, height);
|
|
||||||
var frameCount = stream.ReadUInt16();
|
|
||||||
|
|
||||||
var frames = new FrameHeader[frameCount];
|
// First word is zero
|
||||||
Frames = frames.AsReadOnly();
|
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++)
|
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++)
|
for (var i = 0; i < frameCount; i++)
|
||||||
{
|
{
|
||||||
@@ -66,13 +106,13 @@ namespace OpenRA.FileFormats
|
|||||||
if (f.FileOffset == 0)
|
if (f.FileOffset == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
stream.Position = f.FileOffset;
|
s.Position = f.FileOffset;
|
||||||
|
|
||||||
var frameSize = f.Size.Width * f.Size.Height;
|
var frameSize = f.Size.Width * f.Size.Height;
|
||||||
|
|
||||||
// Uncompressed
|
// Uncompressed
|
||||||
if (f.Format == 1 || f.Format == 0)
|
if (f.Format == 1 || f.Format == 0)
|
||||||
f.Data = stream.ReadBytes(frameSize);
|
f.Data = s.ReadBytes(frameSize);
|
||||||
|
|
||||||
// Uncompressed scanlines
|
// Uncompressed scanlines
|
||||||
else if (f.Format == 2)
|
else if (f.Format == 2)
|
||||||
@@ -80,9 +120,9 @@ namespace OpenRA.FileFormats
|
|||||||
f.Data = new byte[frameSize];
|
f.Data = new byte[frameSize];
|
||||||
for (var j = 0; j < f.Size.Height; j++)
|
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;
|
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];
|
f.Data = new byte[frameSize];
|
||||||
for (var j = 0; j < f.Size.Height; j++)
|
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;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
102
OpenRA.Mods.Common/SpriteLoaders/TmpRALoader.cs
Normal file
102
OpenRA.Mods.Common/SpriteLoaders/TmpRALoader.cs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.SpriteLoaders
|
||||||
|
{
|
||||||
|
public class TmpRALoader : ISpriteLoader
|
||||||
|
{
|
||||||
|
class TmpRAFrame : ISpriteFrame
|
||||||
|
{
|
||||||
|
public Size Size { get; private set; }
|
||||||
|
public Size FrameSize { get; private set; }
|
||||||
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
|
public TmpRAFrame(byte[] data, Size size)
|
||||||
|
{
|
||||||
|
FrameSize = size;
|
||||||
|
Data = data;
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
Data = new byte[0];
|
||||||
|
else
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTmpRA(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
s.Position += 20;
|
||||||
|
var a = s.ReadUInt32();
|
||||||
|
s.Position += 2;
|
||||||
|
var b = s.ReadUInt16();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return a == 0 && b == 0x2c73;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmpRAFrame[] ParseFrames(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
var width = s.ReadUInt16();
|
||||||
|
var height = s.ReadUInt16();
|
||||||
|
var size = new Size(width, height);
|
||||||
|
|
||||||
|
s.Position += 12;
|
||||||
|
var imgStart = s.ReadUInt32();
|
||||||
|
s.Position += 8;
|
||||||
|
var indexEnd = s.ReadInt32();
|
||||||
|
s.Position += 4;
|
||||||
|
var indexStart = s.ReadInt32();
|
||||||
|
|
||||||
|
s.Position = indexStart;
|
||||||
|
var count = indexEnd - indexStart;
|
||||||
|
var tiles = new TmpRAFrame[count];
|
||||||
|
|
||||||
|
var tilesIndex = 0;
|
||||||
|
foreach (var b in s.ReadBytes(count))
|
||||||
|
{
|
||||||
|
if (b != 255)
|
||||||
|
{
|
||||||
|
s.Position = imgStart + b * width * height;
|
||||||
|
tiles[tilesIndex++] = new TmpRAFrame(s.ReadBytes(width * height), size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tiles[tilesIndex++] = new TmpRAFrame(null, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsTmpRA(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = ParseFrames(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
99
OpenRA.Mods.Common/SpriteLoaders/TmpTDLoader.cs
Normal file
99
OpenRA.Mods.Common/SpriteLoaders/TmpTDLoader.cs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.SpriteLoaders
|
||||||
|
{
|
||||||
|
public class TmpTDLoader : ISpriteLoader
|
||||||
|
{
|
||||||
|
class TmpTDFrame : ISpriteFrame
|
||||||
|
{
|
||||||
|
public Size Size { get; private set; }
|
||||||
|
public Size FrameSize { get; private set; }
|
||||||
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
|
public TmpTDFrame(byte[] data, Size size)
|
||||||
|
{
|
||||||
|
FrameSize = size;
|
||||||
|
Data = data;
|
||||||
|
|
||||||
|
if (data == null)
|
||||||
|
Data = new byte[0];
|
||||||
|
else
|
||||||
|
Size = size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTmpTD(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
|
s.Position += 16;
|
||||||
|
var a = s.ReadUInt32();
|
||||||
|
var b = s.ReadUInt32();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return a == 0 && b == 0x0D1AFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmpTDFrame[] ParseFrames(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
var width = s.ReadUInt16();
|
||||||
|
var height = s.ReadUInt16();
|
||||||
|
var size = new Size(width, height);
|
||||||
|
|
||||||
|
s.Position += 8;
|
||||||
|
var imgStart = s.ReadUInt32();
|
||||||
|
s.Position += 8;
|
||||||
|
var indexEnd = s.ReadInt32();
|
||||||
|
var indexStart = s.ReadInt32();
|
||||||
|
|
||||||
|
s.Position = indexStart;
|
||||||
|
var count = indexEnd - indexStart;
|
||||||
|
var tiles = new TmpTDFrame[count];
|
||||||
|
var tilesIndex = 0;
|
||||||
|
foreach (var b in s.ReadBytes(count))
|
||||||
|
{
|
||||||
|
if (b != 255)
|
||||||
|
{
|
||||||
|
s.Position = imgStart + b * width * height;
|
||||||
|
tiles[tilesIndex++] = new TmpTDFrame(s.ReadBytes(width * height), size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
tiles[tilesIndex++] = new TmpTDFrame(null, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsTmpTD(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = ParseFrames(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ using System.Linq;
|
|||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Mods.Common.SpriteLoaders;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.UtilityCommands
|
namespace OpenRA.Mods.Common.UtilityCommands
|
||||||
{
|
{
|
||||||
@@ -36,7 +37,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
throw new InvalidOperationException("All frames must be the same size");
|
throw new InvalidOperationException("All frames must be the same size");
|
||||||
|
|
||||||
using (var destStream = File.Create(dest))
|
using (var destStream = File.Create(dest))
|
||||||
ShpReader.Write(destStream, size, frames.Select(f => ToBytes(f)));
|
ShpTDSprite.Write(destStream, size, frames.Select(f => ToBytes(f)));
|
||||||
|
|
||||||
Console.WriteLine(dest + " saved.");
|
Console.WriteLine(dest + " saved.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,19 +41,17 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
|
|
||||||
var palette = new ImmutablePalette(args[2], shadowIndex);
|
var palette = new ImmutablePalette(args[2], shadowIndex);
|
||||||
|
|
||||||
ISpriteSource source;
|
var frames = new SpriteLoader(modData.SpriteLoaders, new string[0], null)
|
||||||
using (var stream = File.OpenRead(src))
|
.LoadAllFrames(src);
|
||||||
source = SpriteSource.LoadSpriteSource(stream, src);
|
|
||||||
|
|
||||||
// The r8 padding requires external information that we can't access here.
|
var usePadding = !args.Contains("--nopadding");
|
||||||
var usePadding = !(args.Contains("--nopadding") || source is R8Reader);
|
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var prefix = Path.GetFileNameWithoutExtension(src);
|
var prefix = Path.GetFileNameWithoutExtension(src);
|
||||||
|
|
||||||
foreach (var frame in source.Frames)
|
foreach (var frame in frames)
|
||||||
{
|
{
|
||||||
var frameSize = usePadding ? frame.FrameSize : frame.Size;
|
var frameSize = usePadding && !frame.DisableExportPadding ? frame.FrameSize : frame.Size;
|
||||||
var offset = usePadding ? (frame.Offset - 0.5f * new float2(frame.Size - frame.FrameSize)).ToInt2() : int2.Zero;
|
var offset = usePadding && !frame.DisableExportPadding ? (frame.Offset - 0.5f * new float2(frame.Size - frame.FrameSize)).ToInt2() : int2.Zero;
|
||||||
|
|
||||||
// shp(ts) may define empty frames
|
// shp(ts) may define empty frames
|
||||||
if (frameSize.Width == 0 && frameSize.Height == 0)
|
if (frameSize.Width == 0 && frameSize.Height == 0)
|
||||||
@@ -69,7 +67,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
|
||||||
|
|
||||||
// Clear the frame
|
// Clear the frame
|
||||||
if (usePadding)
|
if (usePadding && !frame.DisableExportPadding)
|
||||||
{
|
{
|
||||||
var clearRow = new byte[data.Stride];
|
var clearRow = new byte[data.Stride];
|
||||||
for (var i = 0; i < frameSize.Height; i++)
|
for (var i = 0; i < frameSize.Height; i++)
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ using OpenRA.Traits;
|
|||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
using OpenRA.FileFormats;
|
using OpenRA.FileFormats;
|
||||||
using OpenRA.FileSystem;
|
using OpenRA.FileSystem;
|
||||||
|
using OpenRA.Mods.Common.SpriteLoaders;
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.UtilityCommands
|
namespace OpenRA.Mods.Common.UtilityCommands
|
||||||
{
|
{
|
||||||
@@ -65,12 +66,14 @@ namespace OpenRA.Mods.Common.UtilityCommands
|
|||||||
.Where(a => !remap.ContainsValue(a))
|
.Where(a => !remap.ContainsValue(a))
|
||||||
.MinBy(a => ColorDistance(destPalette[a], srcPalette[i]));
|
.MinBy(a => ColorDistance(destPalette[a], srcPalette[i]));
|
||||||
|
|
||||||
var srcImage = ShpReader.Load(args[3]);
|
using (var s = File.OpenRead(args[3]))
|
||||||
|
|
||||||
using (var destStream = File.Create(args[4]))
|
using (var destStream = File.Create(args[4]))
|
||||||
ShpReader.Write(destStream, srcImage.Size,
|
{
|
||||||
|
var srcImage = new ShpTDSprite(s);
|
||||||
|
ShpTDSprite.Write(destStream, srcImage.Size,
|
||||||
srcImage.Frames.Select(im => im.Data.Select(px => (byte)remap[px]).ToArray()));
|
srcImage.Frames.Select(im => im.Data.Select(px => (byte)remap[px]).ToArray()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ColorDistance(uint a, uint b)
|
static int ColorDistance(uint a, uint b)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2014 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. For more information,
|
|
||||||
* see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using OpenRA.FileFormats;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.UtilityCommands
|
|
||||||
{
|
|
||||||
class TransposeShpCommand : IUtilityCommand
|
|
||||||
{
|
|
||||||
public string Name { get { return "--transpose"; } }
|
|
||||||
|
|
||||||
[Desc("SRCSHP DESTSHP START N M [START N M ...]",
|
|
||||||
"Transpose the N*M block of frames starting at START.")]
|
|
||||||
public void Run(ModData modData, string[] args)
|
|
||||||
{
|
|
||||||
var srcImage = ShpReader.Load(args[1]);
|
|
||||||
|
|
||||||
var srcFrames = srcImage.Frames;
|
|
||||||
var destFrames = srcImage.Frames.ToArray();
|
|
||||||
|
|
||||||
for (var z = 3; z < args.Length - 2; z += 3)
|
|
||||||
{
|
|
||||||
var start = Exts.ParseIntegerInvariant(args[z]);
|
|
||||||
var m = Exts.ParseIntegerInvariant(args[z + 1]);
|
|
||||||
var n = Exts.ParseIntegerInvariant(args[z + 2]);
|
|
||||||
|
|
||||||
for (var i = 0; i < m; i++)
|
|
||||||
for (var j = 0; j < n; j++)
|
|
||||||
destFrames[start + i * n + j] = srcFrames[start + j * m + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var destStream = File.Create(args[2]))
|
|
||||||
ShpReader.Write(destStream, srcImage.Size, destFrames.Select(f => f.Data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -84,6 +84,7 @@
|
|||||||
<Compile Include="Widgets\SlidingContainerWidget.cs" />
|
<Compile Include="Widgets\SlidingContainerWidget.cs" />
|
||||||
<Compile Include="Widgets\Logic\IngameChromeLogic.cs" />
|
<Compile Include="Widgets\Logic\IngameChromeLogic.cs" />
|
||||||
<Compile Include="ChooseBuildTabOnSelect.cs" />
|
<Compile Include="ChooseBuildTabOnSelect.cs" />
|
||||||
|
<Compile Include="R8Loader.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -8,23 +8,26 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using OpenRA.Graphics;
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
namespace OpenRA.FileFormats
|
namespace OpenRA.Mods.D2k.SpriteLoaders
|
||||||
{
|
{
|
||||||
public class R8Reader : ISpriteSource
|
public class R8Loader : ISpriteLoader
|
||||||
{
|
{
|
||||||
class R8Image : ISpriteFrame
|
class R8Frame : ISpriteFrame
|
||||||
{
|
{
|
||||||
public Size Size { get; private set; }
|
public Size Size { get; private set; }
|
||||||
public Size FrameSize { get; private set; }
|
public Size FrameSize { get; private set; }
|
||||||
public float2 Offset { get; private set; }
|
public float2 Offset { get; private set; }
|
||||||
public byte[] Data { get; set; }
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return true; } }
|
||||||
|
|
||||||
public R8Image(Stream s)
|
public R8Frame(Stream s)
|
||||||
{
|
{
|
||||||
// Scan forward until we find some data
|
// Scan forward until we find some data
|
||||||
var type = s.ReadUInt8();
|
var type = s.ReadUInt8();
|
||||||
@@ -61,20 +64,41 @@ namespace OpenRA.FileFormats
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<ISpriteFrame> Frames { get; private set; }
|
bool IsR8(Stream s)
|
||||||
public bool CacheWhenLoadingTileset { get { return true; } }
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
|
||||||
public readonly int ImageCount;
|
// First byte is nonzero
|
||||||
public R8Reader(Stream stream)
|
if (s.ReadUInt8() == 0)
|
||||||
{
|
{
|
||||||
var frames = new List<R8Image>();
|
s.Position = start;
|
||||||
while (stream.Position < stream.Length)
|
return false;
|
||||||
{
|
|
||||||
frames.Add(new R8Image(stream));
|
|
||||||
ImageCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Frames = frames.ToArray().AsReadOnly();
|
// Check the format of the first frame
|
||||||
|
s.Position = start + 25;
|
||||||
|
var d = s.ReadUInt8();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return d == 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsR8(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = s.Position;
|
||||||
|
var tmp = new List<R8Frame>();
|
||||||
|
while (s.Position < s.Length)
|
||||||
|
tmp.Add(new R8Frame(s));
|
||||||
|
s.Position = start;
|
||||||
|
|
||||||
|
frames = tmp.ToArray();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -56,6 +56,7 @@
|
|||||||
<Compile Include="TiberianSunRefinery.cs" />
|
<Compile Include="TiberianSunRefinery.cs" />
|
||||||
<Compile Include="Render\WithVoxelWalkerBody.cs" />
|
<Compile Include="Render\WithVoxelWalkerBody.cs" />
|
||||||
<Compile Include="Render\WithVoxelUnloadBody.cs" />
|
<Compile Include="Render\WithVoxelUnloadBody.cs" />
|
||||||
|
<Compile Include="SpriteLoaders\TmpTSLoader.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
|||||||
121
OpenRA.Mods.TS/SpriteLoaders/TmpTSLoader.cs
Normal file
121
OpenRA.Mods.TS/SpriteLoaders/TmpTSLoader.cs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2014 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. For more information,
|
||||||
|
* see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using OpenRA.FileFormats;
|
||||||
|
using OpenRA.Graphics;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.TS.SpriteLoaders
|
||||||
|
{
|
||||||
|
public class TmpTSLoader : ISpriteLoader
|
||||||
|
{
|
||||||
|
class TmpTSFrame : ISpriteFrame
|
||||||
|
{
|
||||||
|
public Size Size { get; private set; }
|
||||||
|
public Size FrameSize { get { return Size; } }
|
||||||
|
public float2 Offset { get { return float2.Zero; } }
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
public bool DisableExportPadding { get { return false; } }
|
||||||
|
|
||||||
|
public TmpTSFrame(Stream s, Size size)
|
||||||
|
{
|
||||||
|
if (s.Position != 0)
|
||||||
|
{
|
||||||
|
Size = size;
|
||||||
|
|
||||||
|
// Ignore tile header for now
|
||||||
|
s.Position += 52;
|
||||||
|
|
||||||
|
Data = new byte[size.Width * size.Height];
|
||||||
|
|
||||||
|
// Unpack tile data
|
||||||
|
var width = 4;
|
||||||
|
for (var i = 0; i < size.Height; i++)
|
||||||
|
{
|
||||||
|
var start = i * size.Width + (size.Width - width) / 2;
|
||||||
|
for (var j = 0; j < width; j++)
|
||||||
|
Data[start + j] = s.ReadUInt8();
|
||||||
|
|
||||||
|
width += (i < size.Height / 2 - 1 ? 1 : -1) * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore Z-data for now
|
||||||
|
// Ignore extra data for now
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Data = new byte[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsTmpTS(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
s.Position += 8;
|
||||||
|
var sx = s.ReadUInt32();
|
||||||
|
var sy = s.ReadUInt32();
|
||||||
|
|
||||||
|
// Find the first non-empty frame
|
||||||
|
var offset = s.ReadUInt32();
|
||||||
|
while (offset == 0)
|
||||||
|
offset = s.ReadUInt32();
|
||||||
|
|
||||||
|
if (offset > s.Length - 52)
|
||||||
|
{
|
||||||
|
s.Position = start;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = offset + 12;
|
||||||
|
var test = s.ReadUInt32();
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return test == sx * sy / 2 + 52;
|
||||||
|
}
|
||||||
|
|
||||||
|
TmpTSFrame[] ParseFrames(Stream s)
|
||||||
|
{
|
||||||
|
var start = s.Position;
|
||||||
|
var templateWidth = s.ReadUInt32();
|
||||||
|
var templateHeight = s.ReadUInt32();
|
||||||
|
var tileWidth = s.ReadInt32();
|
||||||
|
var tileHeight = s.ReadInt32();
|
||||||
|
var size = new Size(tileWidth, tileHeight);
|
||||||
|
var offsets = new uint[templateWidth * templateHeight];
|
||||||
|
for (var i = 0; i < offsets.Length; i++)
|
||||||
|
offsets[i] = s.ReadUInt32();
|
||||||
|
|
||||||
|
var tiles = new TmpTSFrame[offsets.Length];
|
||||||
|
for (var i = 0; i < offsets.Length; i++)
|
||||||
|
{
|
||||||
|
s.Position = offsets[i];
|
||||||
|
tiles[i] = new TmpTSFrame(s, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = start;
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
|
||||||
|
{
|
||||||
|
if (!IsTmpTS(s))
|
||||||
|
{
|
||||||
|
frames = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
frames = ParseFrames(s);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -210,3 +210,5 @@ Missions:
|
|||||||
mods/cnc/missions.yaml
|
mods/cnc/missions.yaml
|
||||||
|
|
||||||
SupportsMapsFrom: cnc
|
SupportsMapsFrom: cnc
|
||||||
|
|
||||||
|
SpriteFormats: ShpTD, TmpTD, ShpTS, TmpRA
|
||||||
@@ -188,3 +188,5 @@ LuaScripts:
|
|||||||
mods/common/lua/facing.lua
|
mods/common/lua/facing.lua
|
||||||
|
|
||||||
SupportsMapsFrom: d2k
|
SupportsMapsFrom: d2k
|
||||||
|
|
||||||
|
SpriteFormats: R8, ShpTD, TmpRA
|
||||||
@@ -50,3 +50,5 @@ Fonts:
|
|||||||
Size:10
|
Size:10
|
||||||
|
|
||||||
LobbyDefaults:
|
LobbyDefaults:
|
||||||
|
|
||||||
|
SpriteFormats: ShpTD
|
||||||
@@ -207,3 +207,5 @@ Missions:
|
|||||||
mods/ra/missions.yaml
|
mods/ra/missions.yaml
|
||||||
|
|
||||||
SupportsMapsFrom: ra
|
SupportsMapsFrom: ra
|
||||||
|
|
||||||
|
SpriteFormats: ShpTD, TmpRA, TmpTD, ShpTS
|
||||||
@@ -229,3 +229,5 @@ LuaScripts:
|
|||||||
mods/common/lua/facing.lua
|
mods/common/lua/facing.lua
|
||||||
|
|
||||||
SupportsMapsFrom: ts
|
SupportsMapsFrom: ts
|
||||||
|
|
||||||
|
SpriteFormats: ShpTS, TmpTS, ShpTD
|
||||||
Reference in New Issue
Block a user