mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-18 07:02:29 +03:00
Add support for loading IMG files.
This commit is contained in:
parent
f28c54351f
commit
939288b10b
@ -1,17 +1,52 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.IO;
|
||||||
using Syroot.Worms.Gen2;
|
using Syroot.Worms.Gen2;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Syroot.Worms.Test
|
namespace Syroot.Worms.Test
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the main class of the application containing the program entry point.
|
||||||
|
/// </summary>
|
||||||
internal class Program
|
internal class Program
|
||||||
{
|
{
|
||||||
|
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private static readonly string[] _testPaths = { @"C:\Games\Worms Armageddon 3.7.2.1", @"E:\" };
|
||||||
|
|
||||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private static void Main(string[] args)
|
private static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Archive archive = new Archive(@"D:\Archive\Games\Worms\Worms Armageddon\DATA\Gfx\Gfx0.dir");
|
//foreach (string dirFile in GetFiles("*.dir"))
|
||||||
archive.Save(@"D:\Pictures\test.dir");
|
//{
|
||||||
Archive archive2 = new Archive(@"D:\Pictures\test.dir");
|
// Console.WriteLine($"Loading {dirFile}...");
|
||||||
|
// Archive archive = new Archive(dirFile);
|
||||||
|
// foreach (string entry in archive.Keys)
|
||||||
|
// {
|
||||||
|
// Console.WriteLine($"\t{entry}");
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
foreach (string imgFile in GetFiles("*.img"))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Loading {imgFile}...");
|
||||||
|
Image image = new Image(imgFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<string> GetFiles(string wildcard)
|
||||||
|
{
|
||||||
|
List<string> files = new List<string>();
|
||||||
|
foreach (string testPath in _testPaths)
|
||||||
|
{
|
||||||
|
files.AddRange(Directory.GetFiles(testPath, wildcard, SearchOption.AllDirectories));
|
||||||
|
}
|
||||||
|
return files;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.26403.3
|
VisualStudioVersion = 15.0.26403.7
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
namespace Syroot.Worms.Core
|
namespace Syroot.Worms.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents extension methods for <see cref="byte[]"/> instances.
|
/// Represents extension methods for byte array instances.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ByteArrayExtensions
|
internal static class ByteArrayExtensions
|
||||||
{
|
{
|
||||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns <c>true</c> if the current <see cref="byte[]"/> instance holds the same values as the given one.
|
/// Returns <c>true</c> if the current byte array instance holds the same values as the given one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="self">The extended <see cref="byte[]"/> instance.</param>
|
/// <param name="self">The extended byte array instance.</param>
|
||||||
/// <param name="other">The <see cref="byte[]"/> instance to compare with.</param>
|
/// <param name="other">The byte array instance to compare with.</param>
|
||||||
/// <returns><c>true</c> if both instances hold the same values, otherwise <c>false</c>.</returns>
|
/// <returns><c>true</c> if both instances hold the same values, otherwise <c>false</c>.</returns>
|
||||||
internal static bool Compare(this byte[] self, byte[] other)
|
internal static bool Compare(this byte[] self, byte[] other)
|
||||||
{
|
{
|
||||||
|
54
src/Syroot.Worms/Core/Team17Compression.cs
Normal file
54
src/Syroot.Worms/Core/Team17Compression.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace Syroot.Worms.Core
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents methods to decompress data which is compressed using Team17's internal compression algorithm for
|
||||||
|
/// graphic file formats.
|
||||||
|
/// S. http://worms2d.info/Team17_compression.
|
||||||
|
/// </summary>
|
||||||
|
internal static class Team17Compression
|
||||||
|
{
|
||||||
|
public static bool Decompress(BinaryReader b, ref byte[] dStream)
|
||||||
|
{
|
||||||
|
int cmd;
|
||||||
|
int output = 0; //offset of next write
|
||||||
|
while ((cmd = b.ReadByte()) != -1)
|
||||||
|
{ //read a byte
|
||||||
|
if ((cmd & 0x80) == 0)
|
||||||
|
{ //command: 1 byte (color)
|
||||||
|
dStream[output++] = (byte)cmd;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int arg1 = (cmd >> 3) & 0xF; //arg1=bits 2-5
|
||||||
|
int arg2 = b.ReadByte();
|
||||||
|
if (arg2 == -1)
|
||||||
|
return false;
|
||||||
|
arg2 = ((cmd << 8) | arg2) & 0x7FF; //arg2=bits 6-16
|
||||||
|
if (arg1 == 0)
|
||||||
|
{
|
||||||
|
if (arg2 == 0) //command: 0x80 0x00
|
||||||
|
return false;
|
||||||
|
int arg3 = b.ReadByte();
|
||||||
|
if (arg3 == -1)
|
||||||
|
return false;
|
||||||
|
output = CopyData(output, arg2, arg3 + 18, ref dStream); //command: 3 bytes
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
output = CopyData(output, arg2 + 1, arg1 + 2, ref dStream); //command: 2 bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int CopyData(int dOffset, int cOffset, int Repeat, ref byte[] dStream)
|
||||||
|
{
|
||||||
|
for (; Repeat > 0; Repeat--)
|
||||||
|
dStream[dOffset] = dStream[dOffset++ - cOffset];
|
||||||
|
return dOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,8 +16,8 @@ namespace Syroot.Worms.Gen2
|
|||||||
{
|
{
|
||||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
private static readonly int _signature = 0x1A524944;
|
private const int _signature = 0x1A524944; // "DIR", 0x1A
|
||||||
private static readonly int _tocSignature = 0x0000000A;
|
private const int _tocSignature = 0x0000000A;
|
||||||
|
|
||||||
private const int _hashBits = 10;
|
private const int _hashBits = 10;
|
||||||
private const int _hashSize = 1 << _hashBits;
|
private const int _hashSize = 1 << _hashBits;
|
||||||
@ -63,7 +63,7 @@ namespace Syroot.Worms.Gen2
|
|||||||
int signature = reader.ReadInt32();
|
int signature = reader.ReadInt32();
|
||||||
if (signature != _signature)
|
if (signature != _signature)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Invalid file signature.");
|
throw new InvalidDataException("Invalid DIR file signature.");
|
||||||
}
|
}
|
||||||
int fileSize = reader.ReadInt32();
|
int fileSize = reader.ReadInt32();
|
||||||
int tocOffset = reader.ReadInt32();
|
int tocOffset = reader.ReadInt32();
|
||||||
@ -73,7 +73,7 @@ namespace Syroot.Worms.Gen2
|
|||||||
int tocSignature = reader.ReadInt32();
|
int tocSignature = reader.ReadInt32();
|
||||||
if (tocSignature != _tocSignature)
|
if (tocSignature != _tocSignature)
|
||||||
{
|
{
|
||||||
throw new InvalidDataException("Invalid table of contents signature.");
|
throw new InvalidDataException("Invalid DIR table of contents signature.");
|
||||||
}
|
}
|
||||||
// Generate a data dictionary out of the hash table and file entries.
|
// Generate a data dictionary out of the hash table and file entries.
|
||||||
int[] hashTable = reader.ReadInt32s(_hashSize);
|
int[] hashTable = reader.ReadInt32s(_hashSize);
|
||||||
|
@ -1,10 +1,157 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Syroot.IO;
|
||||||
|
using Syroot.Maths;
|
||||||
|
using Syroot.Worms.Core;
|
||||||
|
|
||||||
namespace Syroot.Worms.Gen2
|
namespace Syroot.Worms.Gen2
|
||||||
{
|
{
|
||||||
class Image
|
/// <summary>
|
||||||
|
/// Represents a (palettized) graphical image stored in an IMG file, possibly compressed.
|
||||||
|
/// Used by W2, WA and WWP. S. https://worms2d.info/Image_file.
|
||||||
|
/// </summary>
|
||||||
|
public class Image
|
||||||
{
|
{
|
||||||
|
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
private const int _signature = 0x1A474D49; // "IMG", 0x1A
|
||||||
|
|
||||||
|
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Image"/> class, loading the data from the given
|
||||||
|
/// <see cref="Stream"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||||
|
public Image(Stream stream)
|
||||||
|
{
|
||||||
|
Load(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="Image"/> class, loading the data from the given file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||||
|
public Image(string fileName)
|
||||||
|
{
|
||||||
|
Load(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- PROPERTIES ---------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an optional description of the image contents.
|
||||||
|
/// </summary>
|
||||||
|
public string Description { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of bits required to describe a color per pixel.
|
||||||
|
/// </summary>
|
||||||
|
public int BitsPerPixel { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color palette of the image. The first color must always be black.
|
||||||
|
/// </summary>
|
||||||
|
public Color[] Palette { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width of the image in pixels.
|
||||||
|
/// </summary>
|
||||||
|
public int Width { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of the image in pixels.
|
||||||
|
/// </summary>
|
||||||
|
public int Height { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the data of the image pixels.
|
||||||
|
/// </summary>
|
||||||
|
public byte[] Data { get; private set; }
|
||||||
|
|
||||||
|
// ---- METHODS (PUBLIC) ---------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the data from the given <see cref="Stream"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The <see cref="Stream"/> to load the data from.</param>
|
||||||
|
public void Load(Stream stream)
|
||||||
|
{
|
||||||
|
using (BinaryDataReader reader = new BinaryDataReader(stream, Encoding.ASCII))
|
||||||
|
{
|
||||||
|
// Read the header.
|
||||||
|
int signature = reader.ReadInt32();
|
||||||
|
if (signature != _signature)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid IMG file signature.");
|
||||||
|
}
|
||||||
|
int fileSize = reader.ReadInt32();
|
||||||
|
|
||||||
|
// Read an optional string describing the image contents or the bits per pixel.
|
||||||
|
BitsPerPixel = reader.ReadByte();
|
||||||
|
if (BitsPerPixel == 0)
|
||||||
|
{
|
||||||
|
Description = String.Empty;
|
||||||
|
BitsPerPixel = reader.ReadByte();
|
||||||
|
}
|
||||||
|
else if (BitsPerPixel > 32)
|
||||||
|
{
|
||||||
|
Description = (char)BitsPerPixel + reader.ReadString(BinaryStringFormat.ZeroTerminated);
|
||||||
|
BitsPerPixel = reader.ReadByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read image flags describing the format and availability of the following contents.
|
||||||
|
Flags flags = (Flags)reader.ReadByte();
|
||||||
|
|
||||||
|
// Read the image palette if available. The first color of the palette is implicitly black.
|
||||||
|
if (flags.HasFlag(Flags.Palettized))
|
||||||
|
{
|
||||||
|
int colorCount = reader.ReadInt16();
|
||||||
|
Palette = new Color[colorCount + 1];
|
||||||
|
Palette[0] = Color.Black;
|
||||||
|
for (int i = 1; i <= colorCount; i++)
|
||||||
|
{
|
||||||
|
Palette[i] = new Color(reader.ReadByte(), reader.ReadByte(), reader.ReadByte());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Width = reader.ReadInt16();
|
||||||
|
Height = reader.ReadInt16();
|
||||||
|
|
||||||
|
// Read the image data, which might be compressed.
|
||||||
|
byte[] data = new byte[Width * Height * (BitsPerPixel / 8)];
|
||||||
|
if (flags.HasFlag(Flags.Compressed))
|
||||||
|
{
|
||||||
|
Team17Compression.Decompress(reader, ref data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = reader.ReadBytes(data.Length);
|
||||||
|
}
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads the data from the given file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileName">The name of the file to load the data from.</param>
|
||||||
|
public void Load(string fileName)
|
||||||
|
{
|
||||||
|
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
|
{
|
||||||
|
Load(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- ENUMERATIONS -------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum Flags
|
||||||
|
{
|
||||||
|
Compressed = 1 << 6,
|
||||||
|
Palettized = 1 << 7
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,35 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
<Description>.NET library to load and modify file formats of Team17 Worms games.</Description>
|
||||||
</PropertyGroup>
|
<Copyright>MIT</Copyright>
|
||||||
|
<AssemblyName>Syroot.Worms</AssemblyName>
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
<AssemblyTitle>Worms</AssemblyTitle>
|
||||||
<DocumentationFile>bin\Release\netcoreapp1.1\Syroot.Worms.xml</DocumentationFile>
|
<Authors>Syroot</Authors>
|
||||||
|
<VersionPrefix>0.1.0</VersionPrefix>
|
||||||
|
|
||||||
|
<PackageId>Syroot.Worms</PackageId>
|
||||||
|
<PackageTags>worms;team17</PackageTags>
|
||||||
|
<PackageReleaseNotes>Initial alpha release.</PackageReleaseNotes>
|
||||||
|
<PackageIconUrl>https://raw.githubusercontent.com/Syroot/Worms/master/res/Logo.png</PackageIconUrl>
|
||||||
|
<PackageProjectUrl>https://github.com/Syroot/Worms</PackageProjectUrl>
|
||||||
|
<PackageLicenseUrl>https://raw.githubusercontent.com/Syroot/Worms/master/LICENSE</PackageLicenseUrl>
|
||||||
|
<RepositoryType>git</RepositoryType>
|
||||||
|
<RepositoryUrl>https://github.com/Syroot/Worms</RepositoryUrl>
|
||||||
|
|
||||||
|
<TargetFrameworks>netstandard1.6</TargetFrameworks>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Syroot.IO.BinaryData" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Syroot.Maths" Version="1.2.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="Gen1\" />
|
<Folder Include="Gen1\" />
|
||||||
<Folder Include="Gen2\Armageddon\ProjectX\" />
|
<Folder Include="Gen2\Armageddon\ProjectX\" />
|
||||||
<Folder Include="Gen3\" />
|
<Folder Include="Gen3\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Syroot.IO.BinaryData" Version="1.1.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
Loading…
x
Reference in New Issue
Block a user