mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-04-10 19:30:06 +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.IO;
|
||||
using Syroot.Worms.Gen2;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Syroot.Worms.Test
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the main class of the application containing the program entry point.
|
||||
/// </summary>
|
||||
internal class Program
|
||||
{
|
||||
// ---- CONSTANTS ----------------------------------------------------------------------------------------------
|
||||
|
||||
private static readonly string[] _testPaths = { @"C:\Games\Worms Armageddon 3.7.2.1", @"E:\" };
|
||||
|
||||
// ---- METHODS (PRIVATE) --------------------------------------------------------------------------------------
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
Archive archive = new Archive(@"D:\Archive\Games\Worms\Worms Armageddon\DATA\Gfx\Gfx0.dir");
|
||||
archive.Save(@"D:\Pictures\test.dir");
|
||||
Archive archive2 = new Archive(@"D:\Pictures\test.dir");
|
||||
//foreach (string dirFile in GetFiles("*.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
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26403.3
|
||||
VisualStudioVersion = 15.0.26403.7
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Syroot.Worms", "Syroot.Worms\Syroot.Worms.csproj", "{DD76B6AA-5A5A-4FCD-95AA-9552977525A1}"
|
||||
EndProject
|
||||
|
@ -1,17 +1,17 @@
|
||||
namespace Syroot.Worms.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents extension methods for <see cref="byte[]"/> instances.
|
||||
/// Represents extension methods for byte array instances.
|
||||
/// </summary>
|
||||
internal static class ByteArrayExtensions
|
||||
{
|
||||
// ---- METHODS (INTERNAL) -------------------------------------------------------------------------------------
|
||||
|
||||
/// <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>
|
||||
/// <param name="self">The extended <see cref="byte[]"/> instance.</param>
|
||||
/// <param name="other">The <see cref="byte[]"/> instance to compare with.</param>
|
||||
/// <param name="self">The extended byte array instance.</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>
|
||||
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 ----------------------------------------------------------------------------------------------
|
||||
|
||||
private static readonly int _signature = 0x1A524944;
|
||||
private static readonly int _tocSignature = 0x0000000A;
|
||||
private const int _signature = 0x1A524944; // "DIR", 0x1A
|
||||
private const int _tocSignature = 0x0000000A;
|
||||
|
||||
private const int _hashBits = 10;
|
||||
private const int _hashSize = 1 << _hashBits;
|
||||
@ -63,7 +63,7 @@ namespace Syroot.Worms.Gen2
|
||||
int signature = reader.ReadInt32();
|
||||
if (signature != _signature)
|
||||
{
|
||||
throw new InvalidDataException("Invalid file signature.");
|
||||
throw new InvalidDataException("Invalid DIR file signature.");
|
||||
}
|
||||
int fileSize = reader.ReadInt32();
|
||||
int tocOffset = reader.ReadInt32();
|
||||
@ -73,7 +73,7 @@ namespace Syroot.Worms.Gen2
|
||||
int tocSignature = reader.ReadInt32();
|
||||
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.
|
||||
int[] hashTable = reader.ReadInt32s(_hashSize);
|
||||
|
@ -1,10 +1,157 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Syroot.IO;
|
||||
using Syroot.Maths;
|
||||
using Syroot.Worms.Core;
|
||||
|
||||
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">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp1.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DocumentationFile>bin\Release\netcoreapp1.1\Syroot.Worms.xml</DocumentationFile>
|
||||
<Description>.NET library to load and modify file formats of Team17 Worms games.</Description>
|
||||
<Copyright>MIT</Copyright>
|
||||
<AssemblyName>Syroot.Worms</AssemblyName>
|
||||
<AssemblyTitle>Worms</AssemblyTitle>
|
||||
<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>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Syroot.IO.BinaryData" Version="1.1.0" />
|
||||
<PackageReference Include="Syroot.Maths" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Gen1\" />
|
||||
<Folder Include="Gen2\Armageddon\ProjectX\" />
|
||||
<Folder Include="Gen3\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Syroot.IO.BinaryData" Version="1.1.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
Loading…
x
Reference in New Issue
Block a user