Merge pull request #4185 from pchote/frame-rework

Rewrite sprite handling.
This commit is contained in:
Matthias Mailänder
2013-11-30 14:46:54 -08:00
55 changed files with 1623 additions and 2439 deletions

View File

@@ -16,8 +16,9 @@ NEW:
Added a setting for team health bar colors. Added a setting for team health bar colors.
Asset Browser: Asset Browser:
Fixed crashes when trying to load invalid filenames or sprites with just 1 frame. Fixed crashes when trying to load invalid filenames or sprites with just 1 frame.
Added support for browsing the folders for R8 files. Added support for all sprite types.
Added palette chooser and colorpicker dropdown boxes. Added palette chooser and colorpicker dropdown boxes.
Overhauled layout.
Red Alert: Red Alert:
Added MAD Tank. Added MAD Tank.
Fixed a crash in Monster Tank Madness. Fixed a crash in Monster Tank Madness.
@@ -86,6 +87,10 @@ NEW:
Fixed corrupted replays (which would immediately desync). Fixed corrupted replays (which would immediately desync).
Removed runtime mod merging. Removed runtime mod merging.
Added support for map scripting with Lua. Added support for map scripting with Lua.
Overhauled sprite loading code.
Improved error message when loading corrupted sprites.
Rewritten shp(ts) parser makes more efficient use of texture space.
Added support for the dune 2 shp format.
Build system and packages: Build system and packages:
Added GeoIP to Makefile so it is installed properly. Added GeoIP to Makefile so it is installed properly.
Added desktop shortcut creation support to the Makefile and Windows installer. Added desktop shortcut creation support to the Makefile and Windows installer.
@@ -113,7 +118,13 @@ NEW:
Added InvalidTargets property to weapons. Added InvalidTargets property to weapons.
Added modifier support for build palette hotkeys. Added modifier support for build palette hotkeys.
The Requires: option for inheriting from a parent mod has been removed. Mods can directly reference the parent mod files instead. The Requires: option for inheriting from a parent mod has been removed. Mods can directly reference the parent mod files instead.
Icons are now defined in Sequences not Rules. Icons definitions have moved from the unit's rules to its sequence.
Mouse cursors (cursors.yaml) must now specify their file extension.
OpenRA.Utility --png will now generate a set of frames for any sprite type [shp(td)/shp(ts)/shp(d2)/r8/tmp(td)/tmp(ra)].
OpenRA.Utility --shp now requires a list of frames to be combined into a shp.
Removed Utility --tmp-png, --r8, --fromd2 commands (use --png instead).
Removed Asset Browser file extraction / conversion (use the Utility instead).
Unified sprite loading allows any sprite type to be used anywhere: shp can now be used for terrain, and tmp for units.
20130915: 20130915:
All mods: All mods:

View File

@@ -159,8 +159,8 @@ STD_MOD_DEPS = $(STD_MOD_LIBS) $(ralint_TARGET)
mod_ra_SRCS := $(shell find OpenRA.Mods.RA/ -iname '*.cs') mod_ra_SRCS := $(shell find OpenRA.Mods.RA/ -iname '*.cs')
mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll
mod_ra_KIND = library mod_ra_KIND = library
mod_ra_DEPS = $(STD_MOD_DEPS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) mod_ra_DEPS = $(STD_MOD_DEPS) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET)
mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET)
PROGRAMS += mod_ra PROGRAMS += mod_ra
mod_ra: $(mod_ra_TARGET) mod_ra: $(mod_ra_TARGET)

View File

@@ -165,6 +165,7 @@
<Compile Include="Surface.cs"> <Compile Include="Surface.cs">
<SubType>Component</SubType> <SubType>Component</SubType>
</Compile> </Compile>
<Compile Include="TileSetRenderer.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj"> <ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">

View File

@@ -8,8 +8,10 @@
*/ */
#endregion #endregion
using System.Collections;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Traits; using OpenRA.Traits;
@@ -17,11 +19,11 @@ namespace OpenRA.Editor
{ {
static class RenderUtils static class RenderUtils
{ {
static Bitmap RenderShp(ShpReader shp, Palette p) static Bitmap RenderShp(ISpriteSource shp, Palette p)
{ {
var frame = shp[0]; var frame = shp.Frames.First();
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = p.AsSystemPalette(); bitmap.Palette = p.AsSystemPalette();
@@ -33,9 +35,9 @@ namespace OpenRA.Editor
byte* q = (byte*)data.Scan0.ToPointer(); byte* q = (byte*)data.Scan0.ToPointer();
var stride2 = data.Stride; var stride2 = data.Stride;
for (var i = 0; i < shp.Width; i++) for (var i = 0; i < frame.Size.Width; i++)
for (var j = 0; j < shp.Height; j++) for (var j = 0; j < frame.Size.Height; j++)
q[j * stride2 + i] = frame.Image[i + shp.Width * j]; q[j * stride2 + i] = frame.Data[i + frame.Size.Width * j];
} }
bitmap.UnlockBits(data); bitmap.UnlockBits(data);
@@ -78,10 +80,11 @@ namespace OpenRA.Editor
var image = info.SpriteNames[0]; var image = info.SpriteNames[0];
using (var s = FileSystem.OpenWithExts(image, exts)) using (var s = FileSystem.OpenWithExts(image, exts))
{ {
var shp = new ShpReader(s); // TODO: Do this properly
var frame = shp[shp.ImageCount - 1]; var shp = new ShpReader(s) as ISpriteSource;
var frame = shp.Frames.Last();
var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = p.AsSystemPalette(); bitmap.Palette = p.AsSystemPalette();
var data = bitmap.LockBits(bitmap.Bounds(), var data = bitmap.LockBits(bitmap.Bounds(),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
@@ -91,13 +94,13 @@ namespace OpenRA.Editor
byte* q = (byte*)data.Scan0.ToPointer(); byte* q = (byte*)data.Scan0.ToPointer();
var stride = data.Stride; var stride = data.Stride;
for (var i = 0; i < shp.Width; i++) for (var i = 0; i < frame.Size.Width; i++)
for (var j = 0; j < shp.Height; j++) for (var j = 0; j < frame.Size.Height; j++)
q[j * stride + i] = frame.Image[i + shp.Width * j]; q[j * stride + i] = frame.Data[i + frame.Size.Width * j];
} }
bitmap.UnlockBits(data); bitmap.UnlockBits(data);
return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 }; return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.Frames.Count() - 1 };
} }
} }
} }

View File

@@ -11,9 +11,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.IO;
using System.Linq; using System.Linq;
using OpenRA.FileFormats;
namespace OpenRA.FileFormats namespace OpenRA.Editor
{ {
public class TileSetRenderer public class TileSetRenderer
{ {
@@ -21,20 +23,31 @@ namespace OpenRA.FileFormats
Dictionary<ushort, List<byte[]>> templates; Dictionary<ushort, List<byte[]>> templates;
public Size TileSize; public Size TileSize;
List<byte[]> LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8cache, int[] frames) List<byte[]> LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
{ {
if (exts.Contains(".R8") && FileSystem.Exists(filename + ".R8")) ISpriteSource source;
if (!sourceCache.ContainsKey(filename))
{ {
var data = new List<byte[]>(); using (var s = FileSystem.OpenWithExts(filename, exts))
source = SpriteSource.LoadSpriteSource(s, filename);
foreach (var f in frames) if (source.CacheWhenLoadingTileset)
data.Add(f >= 0 ? r8cache[filename][f].Image : null); sourceCache.Add(filename, source);
}
else
source = sourceCache[filename];
return data; if (frames != null)
{
var ret = new List<byte[]>();
var srcFrames = source.Frames.ToArray();
foreach (var i in frames)
ret.Add(srcFrames[i].Data);
return ret;
} }
using (var s = FileSystem.OpenWithExts(filename, exts)) return source.Frames.Select(f => f.Data).ToList();
return new Terrain(s).TileBitmapBytes;
} }
public TileSetRenderer(TileSet tileset, Size tileSize) public TileSetRenderer(TileSet tileset, Size tileSize)
@@ -43,9 +56,9 @@ namespace OpenRA.FileFormats
this.TileSize = tileSize; this.TileSize = tileSize;
templates = new Dictionary<ushort, List<byte[]>>(); templates = new Dictionary<ushort, List<byte[]>>();
var r8cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); var sourceCache = new Dictionary<string, ISpriteSource>();
foreach (var t in TileSet.Templates) foreach (var t in TileSet.Templates)
templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8cache, t.Value.Frames)); templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
} }
public Bitmap RenderTemplate(ushort id, Palette p) public Bitmap RenderTemplate(ushort id, Palette p)

View File

@@ -1,144 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
namespace OpenRA.FileFormats
{
public enum Dune2ImageFlags : int
{
F80_F2 = 0,
F2 = 2,
L16_F80_F2_1 = 1,
L16_F80_F2_2 = 3,
Ln_F80_F2 = 5
}
public class Dune2ImageHeader
{
public readonly Dune2ImageFlags Flags;
public readonly int Width;
public readonly int Height;
public readonly int Slices;
public readonly int FileSize;
public readonly int DataSize;
public readonly byte[] LookupTable;
public byte[] Image;
public Dune2ImageHeader(Stream s)
{
Flags = (Dune2ImageFlags)s.ReadUInt16();
Slices = s.ReadUInt8();
Width = s.ReadUInt16();
Height = s.ReadUInt8();
FileSize = s.ReadUInt16();
DataSize = s.ReadUInt16();
if (Flags == Dune2ImageFlags.L16_F80_F2_1 ||
Flags == Dune2ImageFlags.L16_F80_F2_2 ||
Flags == Dune2ImageFlags.Ln_F80_F2)
{
int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? s.ReadUInt8() : (byte)16;
LookupTable = new byte[n];
for (int i = 0; i < n; i++)
LookupTable[i] = s.ReadUInt8();
}
else
{
LookupTable = new byte[256];
for (int i = 0; i < 256; i++)
LookupTable[i] = (byte)i;
LookupTable[1] = 0x7f;
LookupTable[2] = 0x7e;
LookupTable[3] = 0x7d;
LookupTable[4] = 0x7c;
}
}
public Size Size
{
get { return new Size(Width, Height); }
}
}
public class Dune2ShpReader : IEnumerable<Dune2ImageHeader>
{
public readonly int ImageCount;
List<Dune2ImageHeader> headers = new List<Dune2ImageHeader>();
public Dune2ShpReader(Stream s)
{
ImageCount = s.ReadUInt16();
//Last offset is pointer to end of file.
uint[] offsets = new uint[ImageCount + 1];
uint temp = s.ReadUInt32();
//If fourth byte in file is non-zero, the offsets are two bytes each.
bool twoByteOffsets = (temp & 0xFF0000) > 0;
if (twoByteOffsets)
{
offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes
offsets[1] = (temp & 0xFFFF) + 2;
}
else
offsets[0] = temp + 2;
for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++)
offsets[i] = (twoByteOffsets ? s.ReadUInt16() : s.ReadUInt32()) + 2;
for (int i = 0; i < ImageCount; i++)
{
s.Seek(offsets[i], SeekOrigin.Begin);
Dune2ImageHeader header = new Dune2ImageHeader(s);
byte[] imgData = s.ReadBytes(header.FileSize);
header.Image = new byte[header.Height * header.Width];
//Decode image data
if (header.Flags != Dune2ImageFlags.F2)
{
byte[] tempData = new byte[header.DataSize];
Format80.DecodeInto(imgData, tempData);
Format2.DecodeInto(tempData, header.Image);
}
else
Format2.DecodeInto(imgData, header.Image);
//Lookup values in lookup table
if (header.LookupTable != null)
for (int j = 0; j < header.Image.Length; j++)
header.Image[j] = header.LookupTable[header.Image[j]];
headers.Add(header);
}
}
public Dune2ImageHeader this[int index]
{
get { return headers[index]; }
}
public IEnumerator<Dune2ImageHeader> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}

View File

@@ -12,17 +12,16 @@ using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq;
namespace OpenRA.FileFormats namespace OpenRA.FileFormats
{ {
public class R8Image class R8Image : ISpriteFrame
{ {
public readonly Size Size; public Size Size { get; private set; }
public readonly int2 Offset; public Size FrameSize { get; private set; }
public readonly byte[] Image; public float2 Offset { get; private set; }
public byte[] Data { get; set; }
// Legacy variable. Can be removed when the utility command is made sensible.
public readonly Size FrameSize;
public R8Image(Stream s) public R8Image(Stream s)
{ {
@@ -52,7 +51,7 @@ namespace OpenRA.FileFormats
// Skip alignment byte // Skip alignment byte
s.ReadUInt8(); s.ReadUInt8();
Image = s.ReadBytes(width*height); Data = s.ReadBytes(width*height);
// Ignore palette // Ignore palette
if (type == 1 && paletteOffset != 0) if (type == 1 && paletteOffset != 0)
@@ -60,33 +59,20 @@ namespace OpenRA.FileFormats
} }
} }
public class R8Reader : IEnumerable<R8Image> public class R8Reader : ISpriteSource
{ {
readonly List<R8Image> headers = new List<R8Image>(); readonly List<R8Image> frames = new List<R8Image>();
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
public bool CacheWhenLoadingTileset { get { return true; } }
public readonly int Frames; public readonly int ImageCount;
public R8Reader(Stream stream) public R8Reader(Stream stream)
{ {
while (stream.Position < stream.Length) while (stream.Position < stream.Length)
{ {
headers.Add(new R8Image(stream)); frames.Add(new R8Image(stream));
Frames++; ImageCount++;
} }
} }
public R8Image this[int index]
{
get { return headers[index]; }
}
public IEnumerator<R8Image> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
} }
} }

View File

@@ -0,0 +1,115 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
namespace OpenRA.FileFormats
{
enum Dune2ImageFlags : int
{
F80_F2 = 0,
F2 = 2,
L16_F80_F2_1 = 1,
L16_F80_F2_2 = 3,
Ln_F80_F2 = 5
}
class Frame : 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 Frame(Stream s)
{
var flags = (Dune2ImageFlags)s.ReadUInt16();
s.Position += 1;
var width = s.ReadUInt16();
var height = s.ReadUInt8();
Size = new Size(width, height);
var frameSize = s.ReadUInt16();
var dataSize = s.ReadUInt16();
byte[] table;
if (flags == Dune2ImageFlags.L16_F80_F2_1 ||
flags == Dune2ImageFlags.L16_F80_F2_2 ||
flags == Dune2ImageFlags.Ln_F80_F2)
{
var n = flags == Dune2ImageFlags.Ln_F80_F2 ? s.ReadUInt8() : (byte)16;
table = new byte[n];
for (var i = 0; i < n; i++)
table[i] = s.ReadUInt8();
}
else
{
table = new byte[256];
for (var i = 0; i < 256; i++)
table[i] = (byte)i;
table[1] = 0x7f;
table[2] = 0x7e;
table[3] = 0x7d;
table[4] = 0x7c;
}
// Subtract header size
var imgData = s.ReadBytes(frameSize - 10);
Data = new byte[width * height];
// Decode image data
if (flags != Dune2ImageFlags.F2)
{
var tempData = new byte[dataSize];
Format80.DecodeInto(imgData, tempData);
Format2.DecodeInto(tempData, Data);
}
else
Format2.DecodeInto(imgData, Data);
// Lookup values in lookup table
for (var j = 0; j < Data.Length; j++)
Data[j] = table[Data[j]];
}
}
public class ShpD2Reader : ISpriteSource
{
List<Frame> headers = new List<Frame>();
public IEnumerable<ISpriteFrame> Frames { get { return headers.Cast<ISpriteFrame>(); } }
public bool CacheWhenLoadingTileset { get { return false; } }
public ShpD2Reader(Stream s)
{
var imageCount = s.ReadUInt16();
// Last offset is pointer to end of file.
var offsets = new uint[imageCount + 1];
var temp = s.ReadUInt32();
// If fourth byte in file is non-zero, the offsets are two bytes each.
var twoByteOffset = (temp & 0xFF0000) > 0;
s.Position = 2;
for (var i = 0; i < imageCount + 1; i++)
offsets[i] = (twoByteOffset ? s.ReadUInt16() : s.ReadUInt32()) + 2;
for (var i = 0; i < imageCount; i++)
{
s.Position = offsets[i];
headers.Add(new Frame(s));
}
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS) * Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
@@ -15,153 +15,180 @@ using System.Linq;
namespace OpenRA.FileFormats namespace OpenRA.FileFormats
{ {
public class ImageHeader enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 }
class ImageHeader : ISpriteFrame
{ {
public uint Offset; public Size Size { get { return reader.Size; } }
public Size FrameSize { get { return reader.Size; } }
public float2 Offset { get { return float2.Zero; } }
public byte[] Data { get; set; }
public uint FileOffset;
public Format Format; public Format Format;
public uint RefOffset; public uint RefOffset;
public Format RefFormat; public Format RefFormat;
public ImageHeader RefImage; public ImageHeader RefImage;
public byte[] Image; ShpReader reader;
// Used by ShpWriter
public ImageHeader() { } public ImageHeader() { }
public ImageHeader( BinaryReader reader ) public ImageHeader(Stream stream, ShpReader reader)
{ {
var data = reader.ReadUInt32(); this.reader = reader;
Offset = data & 0xffffff; var data = stream.ReadUInt32();
FileOffset = data & 0xffffff;
Format = (Format)(data >> 24); Format = (Format)(data >> 24);
RefOffset = reader.ReadUInt16(); RefOffset = stream.ReadUInt16();
RefFormat = (Format)reader.ReadUInt16(); RefFormat = (Format)stream.ReadUInt16();
} }
public static readonly int SizeOnDisk = 8;
public void WriteTo(BinaryWriter writer) public void WriteTo(BinaryWriter writer)
{ {
writer.Write(Offset | ((uint)Format << 24)); writer.Write(FileOffset | ((uint)Format << 24));
writer.Write((ushort)RefOffset); writer.Write((ushort)RefOffset);
writer.Write((ushort)RefFormat); writer.Write((ushort)RefFormat);
} }
} }
public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 } public class ShpReader : ISpriteSource
public class ShpReader
{ {
public readonly int ImageCount;
public readonly ushort Width;
public readonly ushort Height;
public Size Size { get { return new Size(Width, Height); } }
readonly List<ImageHeader> headers = new List<ImageHeader>(); readonly List<ImageHeader> headers = new List<ImageHeader>();
public IEnumerable<ISpriteFrame> Frames { get { return headers.Cast<ISpriteFrame>(); } }
public bool CacheWhenLoadingTileset { get { return false; } }
public readonly Size Size;
int recurseDepth = 0; int recurseDepth = 0;
readonly int imageCount;
public ShpReader(Stream stream) public ShpReader(Stream stream)
{ {
using (var reader = new BinaryReader(stream)) imageCount = stream.ReadUInt16();
stream.Position += 4;
var width = stream.ReadUInt16();
var height = stream.ReadUInt16();
Size = new Size(width, height);
stream.Position += 4;
for (var i = 0; i < imageCount; i++)
headers.Add(new ImageHeader(stream, this));
// Skip eof and zero headers
stream.Position += 16;
var offsets = headers.ToDictionary(h => h.FileOffset, h => h);
for (var i = 0; i < imageCount; i++)
{ {
ImageCount = reader.ReadUInt16(); var h = headers[i];
reader.ReadUInt16(); if (h.Format == Format.Format20)
reader.ReadUInt16(); h.RefImage = headers[i - 1];
Width = reader.ReadUInt16();
Height = reader.ReadUInt16();
reader.ReadUInt32();
for (int i = 0 ; i < ImageCount ; i++) else if (h.Format == Format.Format40 && !offsets.TryGetValue(h.RefOffset, out h.RefImage))
headers.Add(new ImageHeader(reader)); throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset));
new ImageHeader(reader); // end-of-file header
new ImageHeader(reader); // all-zeroes header
var offsets = headers.ToDictionary(h => h.Offset, h =>h);
for (int i = 0 ; i < ImageCount ; i++)
{
var h = headers[ i ];
if (h.Format == Format.Format20)
h.RefImage = headers[i - 1];
else if (h.Format == Format.Format40)
if (!offsets.TryGetValue(h.RefOffset, out h.RefImage))
throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.Offset, h.RefOffset));
}
foreach (ImageHeader h in headers)
Decompress(stream, h);
} }
foreach (var h in headers)
Decompress(stream, h);
} }
public ImageHeader this[int index] static byte[] ReadCompressedData(Stream stream, ImageHeader h)
{ {
get { return headers[index]; } stream.Position = h.FileOffset;
// Actually, far too big. There's no length field with the correct length though :(
var compressedLength = (int)(stream.Length - stream.Position);
var compressedBytes = new byte[compressedLength];
stream.Read(compressedBytes, 0, compressedLength);
return compressedBytes;
} }
void Decompress(Stream stream, ImageHeader h) void Decompress(Stream stream, ImageHeader h)
{ {
if (recurseDepth > ImageCount) if (recurseDepth > imageCount)
throw new InvalidDataException("Format20/40 headers contain infinite loop"); throw new InvalidDataException("Format20/40 headers contain infinite loop");
switch(h.Format) switch (h.Format)
{ {
case Format.Format20: case Format.Format20:
case Format.Format40: case Format.Format40:
{
if (h.RefImage.Data == null)
{ {
if (h.RefImage.Image == null) ++recurseDepth;
{ Decompress(stream, h.RefImage);
++recurseDepth; --recurseDepth;
Decompress(stream, h.RefImage); }
--recurseDepth;
} h.Data = CopyImageData(h.RefImage.Data);
Format40.DecodeInto(ReadCompressedData(stream, h), h.Data);
break;
}
h.Image = CopyImageData(h.RefImage.Image);
Format40.DecodeInto(ReadCompressedData(stream, h), h.Image);
break;
}
case Format.Format80: case Format.Format80:
{ {
var imageBytes = new byte[Width * Height]; var imageBytes = new byte[Size.Width * Size.Height];
Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes); Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes);
h.Image = imageBytes; h.Data = imageBytes;
break; break;
} }
default: default:
throw new InvalidDataException(); throw new InvalidDataException();
} }
} }
static byte[] ReadCompressedData(Stream stream, ImageHeader h)
{
stream.Position = h.Offset;
// TODO: Actually, far too big. There's no length field with the correct length though :(
var compressedLength = (int)(stream.Length - stream.Position);
var compressedBytes = new byte[ compressedLength ];
stream.Read( compressedBytes, 0, compressedLength );
return compressedBytes;
}
byte[] CopyImageData(byte[] baseImage) byte[] CopyImageData(byte[] baseImage)
{ {
var imageData = new byte[Width * Height]; var imageData = new byte[Size.Width * Size.Height];
for (int i = 0 ; i < Width * Height ; i++) for (var i = 0; i < Size.Width * Size.Height; i++)
imageData[i] = baseImage[i]; imageData[i] = baseImage[i];
return imageData; return imageData;
} }
public IEnumerable<ImageHeader> Frames { get { return headers; } }
public static ShpReader Load(string filename) public static ShpReader Load(string filename)
{ {
using (var s = File.OpenRead(filename)) using (var s = File.OpenRead(filename))
return new ShpReader(s); return new ShpReader(s);
} }
public static void Write(Stream s, Size size, IEnumerable<byte[]> frames)
{
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
// note: end-of-file and all-zeroes headers
var dataOffset = 14 + (compressedFrames.Length + 2) * 8;
using (var bw = new BinaryWriter(s))
{
bw.Write((ushort)compressedFrames.Length);
bw.Write((ushort)0);
bw.Write((ushort)0);
bw.Write((ushort)size.Width);
bw.Write((ushort)size.Height);
bw.Write((uint)0);
foreach (var f in compressedFrames)
{
var ih = new ImageHeader { Format = Format.Format80, FileOffset = (uint)dataOffset };
dataOffset += f.Length;
ih.WriteTo(bw);
}
var eof = new ImageHeader { FileOffset = (uint)dataOffset };
eof.WriteTo(bw);
var allZeroes = new ImageHeader { };
allZeroes.WriteTo(bw);
foreach (var f in compressedFrames)
bw.Write(f);
}
}
} }
} }

View File

@@ -1,615 +1,112 @@
#region Copyright & License Information #region Copyright & License Information
/* /*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS) * Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made * 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 * available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information, * as published by the Free Software Foundation. For more information,
* see LICENSE. * see COPYING.
*/ */
#endregion #endregion
using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Linq;
namespace OpenRA.FileFormats namespace OpenRA.FileFormats
{ {
class FrameHeader : ISpriteFrame
public struct Header
{ {
public ushort A; public Size Size { get; private set; }
// Unknown public Size FrameSize { get; private set; }
// Width and Height of the images public float2 Offset { get; private set; }
public ushort Width; public byte[] Data { get; set; }
public ushort Height;
public ushort NumImages;
}
public class HeaderImage public readonly uint FileOffset;
{ public readonly byte Format;
public ushort x;
public ushort y;
public ushort cx;
public ushort cy;
// cx and cy are width n height of stored image
public byte compression;
public byte[] align;
public byte[] transparent;
public int zero;
public int offset;
public byte[] Image;
}
public struct SHPData public FrameHeader(Stream stream, Size frameSize)
{
public HeaderImage HeaderImage;
public byte[] Databuffer;
public byte[] FrameImage;
}
public struct SHP
{
public Header Header;
public SHPData[] Data;
}
public class ShpTSReader : IEnumerable<HeaderImage>
{
public readonly int ImageCount;
public readonly ushort Width;
public readonly ushort Height;
public readonly ushort Width2;
public readonly ushort Height2;
public int arroff = 0;
public int erri = 0;
public int errj = 0;
public int errk = 0;
public int errl = 0;
public static int FindNextOffsetFrom(SHP SHP, int Init, int Last)
{ {
int result; var x = stream.ReadUInt16();
result = 0; var y = stream.ReadUInt16();
Last++; var width = stream.ReadUInt16();
while ((result == 0) && (Init < Last)) var height = stream.ReadUInt16();
{
result = SHP.Data[Init].HeaderImage.offset; Offset = new float2(x + 0.5f * (width - frameSize.Width), y + 0.5f * (height - frameSize.Height));
Init++; Size = new Size(width, height);
} FrameSize = frameSize;
return result;
Format = stream.ReadUInt8();
stream.Position += 11;
FileOffset = stream.ReadUInt32();
} }
}
private readonly List<HeaderImage> headers = new List<HeaderImage>(); public class ShpTSReader : ISpriteSource
{
readonly List<FrameHeader> frames = new List<FrameHeader>();
public IEnumerable<ISpriteFrame> Frames { get { return frames.Cast<ISpriteFrame>(); } }
public bool CacheWhenLoadingTileset { get { return false; } }
public ShpTSReader(Stream s) public ShpTSReader(Stream stream)
{ {
stream.ReadUInt16();
var width = stream.ReadUInt16();
var height = stream.ReadUInt16();
var size = new Size(width, height);
var frameCount = stream.ReadUInt16();
SHP SHP = new SHP(); for (var i = 0; i < frameCount; i++)
int FileSize; frames.Add(new FrameHeader(stream, size));
int x;
int k = 0;
int l = 0;
int ImageSize; for (var i = 0; i < frameCount; i++)
int NextOffset; {
var f = frames[i];
if (f.FileOffset == 0)
continue;
byte[] FData; stream.Position = f.FileOffset;
byte cp;
byte[] Databuffer;
FileSize = (int)s.Length; // Uncompressed
// Get Header if (f.Format == 1 || f.Format == 0)
SHP.Header.A = s.ReadUInt16(); f.Data = stream.ReadBytes(f.Size.Width * f.Size.Height);
SHP.Header.Width = s.ReadUInt16();
SHP.Header.Height = s.ReadUInt16();
SHP.Header.NumImages = s.ReadUInt16();
SHP.Data = new SHPData[SHP.Header.NumImages + 1]; // Uncompressed scanlines
else if (f.Format == 2)
ImageCount = SHP.Header.NumImages;
for (x = 1; x <= SHP.Header.NumImages; x++)
{ {
SHP.Data[x].HeaderImage = new HeaderImage(); f.Data = new byte[f.Size.Width * f.Size.Height];
for (var j = 0; j < f.Size.Height; j++)
SHP.Data[x].HeaderImage.x = s.ReadUInt16();
SHP.Data[x].HeaderImage.y = s.ReadUInt16();
SHP.Data[x].HeaderImage.cx = s.ReadUInt16();
SHP.Data[x].HeaderImage.cy = s.ReadUInt16();
SHP.Data[x].HeaderImage.compression = s.ReadUInt8();
SHP.Data[x].HeaderImage.align = s.ReadBytes(3);
s.ReadInt32();
SHP.Data[x].HeaderImage.zero = s.ReadUInt8();
SHP.Data[x].HeaderImage.transparent = s.ReadBytes(3);
SHP.Data[x].HeaderImage.offset = s.ReadInt32();
}
Width = SHP.Header.Width;
Height = SHP.Header.Height;
for (int i = 0; i < ImageCount; i++)
{
headers.Add(SHP.Data[i+1].HeaderImage);
}
// Read and decode each image from the file
for (x = 1; x <= SHP.Header.NumImages; x++)
{
headers[x - 1].Image = new byte[(Width * Height)];
for (int i = 0; i < headers[x - 1].Image.Length; i++)
headers[x - 1].Image[i] = 0;
FData = new byte[(Width * Height)];
// Does it really reads the frame?
if (SHP.Data[x].HeaderImage.offset != 0)
{ {
try var length = stream.ReadUInt16() - 2;
stream.Read(f.Data, f.Size.Width * j, length);
}
}
// RLE-zero compressed scanlines
else if (f.Format == 3)
{
f.Data = new byte[f.Size.Width * f.Size.Height];
for (var j = 0; j < f.Size.Height; j++)
{
var k = j * f.Size.Width;
var length = stream.ReadUInt16() - 2;
while (length > 0)
{ {
// Now it checks the compression: var b = stream.ReadUInt8();
if ((SHP.Data[x].HeaderImage.compression == 3)) length--;
{
// decode it if (b == 0)
// Compression 3
NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages);
if (NextOffset != 0)
{ {
k += stream.ReadUInt8();
ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset; length--;
Databuffer = new byte[ImageSize];
for (int i = 0; i < ImageSize; i++)
{
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
Databuffer[i] = s.ReadUInt8();
}
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref FileSize);
k = 0;
l = 0;
for (int i = 0; i < Height; i++)
{
erri = i;
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
{
errj = j;
errl = l;
errk = k;
arroff = i + j + l;
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
cp = 0;
else
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
FData[i + j + k] = cp;
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
l = l + (SHP.Data[x].HeaderImage.cx - 1);
if (j == (Width - 1))
k = k + (Width - 1);
}
}
//FData = headers[x - 1].Image;
k = 0;
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
{
for (int j = 0; j < Width; j++)
{
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
if (j == (Width - 1))
{
k = k + (Width - 1);
}
}
}
} }
else else
{ f.Data[k++] = b;
ImageSize = 0;
ImageSize = FileSize - SHP.Data[x].HeaderImage.offset;
Databuffer = new byte[ImageSize];
for (int i = 0; i < ImageSize; i++)
{
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
Databuffer[i] = s.ReadUInt8();
}
SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))];
Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
k = 0;
l = 0;
for (int i = 0; i < Height; i++)
{
erri = i;
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
{
errj = j;
errl = l;
errk = k;
arroff = i + j + l;
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
cp = 0;
else
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
FData[i + j + k] = cp;
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
l = l + (SHP.Data[x].HeaderImage.cx - 1);
if (j == (Width - 1))
k = k + (Width - 1);
}
}
//FData = headers[x - 1].Image;
k = 0;
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
{
for (int j = 0; j < Width; j++)
{
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
if (j == (Width - 1))
{
k = k + (Width - 1);
}
}
}
}
} }
else if ((SHP.Data[x].HeaderImage.compression == 2))
{
NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages);
if (NextOffset != 0)
{
ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset;
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
Databuffer = new byte[ImageSize];
for (int i = 0; i < ImageSize; i++)
{
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
Databuffer[i] = s.ReadUInt8();
}
Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
k = 0;
l = 0;
for (int i = 0; i < Height; i++)
{
erri = i;
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
{
errj = j;
errl = l;
errk = k;
arroff = i + j + l;
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
cp = 0;
else
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
FData[i + j + k] = cp;
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
l = l + (SHP.Data[x].HeaderImage.cx - 1);
if (j == (Width - 1))
k = k + (Width - 1);
}
}
//FData = headers[x - 1].Image;
k = 0;
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
{
for (int j = 0; j < Width; j++)
{
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
if (j == (Width - 1))
{
k = k + (Width - 1);
}
}
}
// Compression 2
}
else
{
ImageSize = 0;
ImageSize = FileSize - SHP.Data[x].HeaderImage.offset;
Databuffer = new byte[ImageSize];
for (int i = 0; i < ImageSize; i++)
{
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
Databuffer[i] = s.ReadUInt8();
}
SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))];
Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize);
k = 0;
l = 0;
for (int i = 0; i < Height; i++)
{
erri = i;
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
{
errj = j;
errl = l;
errk = k;
arroff = i + j + l;
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
cp = 0;
else
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
FData[i + j + k] = cp;
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
l = l + (SHP.Data[x].HeaderImage.cx - 1);
if (j == (Width - 1))
k = k + (Width - 1);
}
}
//FData = headers[x - 1].Image;
k = 0;
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
{
for (int j = 0; j < Width; j++)
{
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
if (j == (Width - 1))
{
k = k + (Width - 1);
}
}
}
// Compression 2
}
}
else
{
// Compression 1
ImageSize = (int)(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy);
Databuffer = new byte[ImageSize];
for (int i = 0; i < ImageSize; i++)
{
s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin);
Databuffer[i] = s.ReadUInt8();
}
SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)];
SHP.Data[x].Databuffer = Databuffer;
k = 0;
l = 0;
for (int i = 0; i < Height; i++)
{
erri = i;
for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++)
{
errj = j;
errl = l;
errk = k;
arroff = i + j + l;
if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy)))
cp = 0;
else
cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l];
FData[i + j + k] = cp;
if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1))
l = l + (SHP.Data[x].HeaderImage.cx - 1);
if (j == (Width - 1))
k = k + (Width - 1);
}
}
//FData = headers[x - 1].Image;
k = 0;
for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++)
{
for (int j = 0; j < Width; j++)
{
headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k];
if (j == (Width - 1))
{
k = k + (Width - 1);
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
} }
} }
// Set the shp's databuffer to the result after decompression
}
//Width = Width2;
//Height = Height2;
}
public HeaderImage this[int index]
{
get { return headers[index]; }
}
public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref ushort FullValue)
{
FullValue = (ushort)((Byte2 * 256) + Byte1);
}
public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref uint FullValue)
{
FullValue = (uint)((Byte2 * 256) + Byte1);
}
// Compression 3:
public static void Decode3(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max)
{
int SP;
int DP;
int x;
int y;
int Count;
int v;
int maxdp;
ushort Pos;
maxdp = cx * cy;
SP = 0;
DP = 0;
Pos = 0;
try
{
for (y = 1; y <= cy; y++)
{
ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos);
Count = Pos - 2;
SP = SP + 2;
x = 0;
while (Count > 0)
{
Count = Count - 1;
if ((SP > max) || (DP > maxdp))
{
break;
}
else
{
// SP has reached max value, exit
v = Source[SP];
SP++;
if (v != 0)
{
if ((SP > max) || (DP > maxdp))
{
break;
}
else
{
x++;
Dest[DP] += (byte)v;
}
DP++;
}
else
{
Count -= 1;
v = Source[SP];
SP++;
if ((x + v) > cx)
{
v = cx - x;
}
x = x + v;
while (v > 0)
{
if ((SP > max) || (DP > maxdp))
{
break;
}
else
{
v -= 1;
Dest[DP] = 0;
}
DP++;
// SP has reached max value, exit
}
}
}
}
if ((SP >= max) || (DP >= maxdp))
{
return;
}
// SP has reached max value, exit
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public static void Decode2(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max)
{
int SP;
int DP;
int y;
int Count;
int maxdp;
ushort Pos;
maxdp = cx * cy;
SP = 0;
DP = 0;
Pos = 0;
try
{
for (y = 1; y <= cy; y++)
{
ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos);
Count = Pos - 2;
SP += 2;
while (Count > 0)
{
Count -= 1;
if ((SP > max) || (DP > maxdp))
{
return;
}
// SP has reached max value, exit
Dest[DP] = Source[SP];
SP++;
DP++;
}
if ((SP >= max) || (DP >= maxdp))
{
return;
}
// SP has reached max value, exit
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
} }
} }
public IEnumerator<HeaderImage> GetEnumerator()
{
return headers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Size Size { get { return new Size(Width, Height); } }
} }
} }

View File

@@ -1,56 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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.IO;
using System.Linq;
namespace OpenRA.FileFormats.Graphics
{
// format80-only SHP writer
public static class ShpWriter
{
public static void Write(Stream s, int width, int height, IEnumerable<byte[]> frames)
{
var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray();
// note: end-of-file and all-zeroes headers
var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk;
using (var bw = new BinaryWriter(s))
{
bw.Write((ushort)compressedFrames.Length);
bw.Write((ushort)0); // unused
bw.Write((ushort)0); // unused
bw.Write((ushort)width);
bw.Write((ushort)height);
bw.Write((uint)0); // unused
foreach (var f in compressedFrames)
{
var ih = new ImageHeader { Format = Format.Format80, Offset = (uint)dataOffset };
dataOffset += f.Length;
ih.WriteTo(bw);
}
var eof = new ImageHeader { Offset = (uint)dataOffset };
eof.WriteTo(bw);
var allZeroes = new ImageHeader { };
allZeroes.WriteTo(bw);
foreach (var f in compressedFrames)
bw.Write(f);
}
}
}
}

View File

@@ -0,0 +1,236 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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 System.Linq;
namespace OpenRA.FileFormats
{
public interface ISpriteFrame
{
Size Size { get; }
Size FrameSize { get; }
float2 Offset { get; }
byte[] Data { get; }
}
public interface ISpriteSource
{
IEnumerable<ISpriteFrame> Frames { get; }
bool CacheWhenLoadingTileset { get; }
}
public enum SpriteType { Unknown, ShpTD, ShpTS, ShpD2, TmpTD, TmpRA, 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 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 (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.ShpD2:
return new ShpD2Reader(s);
case SpriteType.Unknown:
default:
throw new InvalidDataException(filename + " is not a valid sprite file");
}
}
}
}

View File

@@ -0,0 +1,50 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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 System.Linq;
namespace OpenRA.FileFormats
{
public class TmpRAReader : ISpriteSource
{
readonly List<TmpTile> tiles = new List<TmpTile>();
public IEnumerable<ISpriteFrame> Frames { get { return tiles.Cast<ISpriteFrame>(); } }
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;
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
{
if (b != 255)
{
s.Position = imgStart + b * width * height;
tiles.Add(new TmpTile(s.ReadBytes(width * height), size));
}
else
tiles.Add(new TmpTile(null, size));
}
}
}
}

View File

@@ -0,0 +1,68 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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.Linq;
using System.IO;
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
{
readonly List<TmpTile> tiles = new List<TmpTile>();
public IEnumerable<ISpriteFrame> Frames { get { return tiles.Cast<ISpriteFrame>(); } }
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;
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
{
if (b != 255)
{
s.Position = imgStart + b * width * height;
tiles.Add(new TmpTile(s.ReadBytes(width * height), size));
}
else
tiles.Add(new TmpTile(null, size));
}
}
}
}

View File

@@ -1,77 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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.IO;
namespace OpenRA.FileFormats
{
public class Terrain
{
public readonly List<byte[]> TileBitmapBytes = new List<byte[]>();
public readonly int Width;
public readonly int Height;
public Terrain(Stream s)
{
// Try loading as a cnc .tem
Width = s.ReadUInt16();
Height = s.ReadUInt16();
/*NumTiles = */s.ReadUInt16();
/*Zero1 = */s.ReadUInt16();
/*uint Size = */s.ReadUInt32();
var imgStart = s.ReadUInt32();
/*Zero2 = */s.ReadUInt32();
int indexEnd, indexStart;
// ID1 = FFFFh for cnc
if (s.ReadUInt16() == 65535)
{
/*ID2 = */s.ReadUInt16();
indexEnd = s.ReadInt32();
indexStart = s.ReadInt32();
}
else
{
// Load as a ra .tem
s.Position = 0;
Width = s.ReadUInt16();
Height = s.ReadUInt16();
/*NumTiles = */s.ReadUInt16();
s.ReadUInt16();
/*XDim = */s.ReadUInt16();
/*YDim = */s.ReadUInt16();
/*uint FileSize = */s.ReadUInt32();
imgStart = s.ReadUInt32();
s.ReadUInt32();
s.ReadUInt32();
indexEnd = s.ReadInt32();
s.ReadUInt32();
indexStart = s.ReadInt32();
}
s.Position = indexStart;
foreach (byte b in s.ReadBytes(indexEnd - indexStart))
{
if (b != 255)
{
s.Position = imgStart + b * Width * Height;
TileBitmapBytes.Add(s.ReadBytes(Width * Height));
}
else
TileBitmapBytes.Add(null);
}
}
}
}

View File

@@ -90,19 +90,16 @@
<Compile Include="FileFormats\Format40.cs" /> <Compile Include="FileFormats\Format40.cs" />
<Compile Include="FileFormats\Format80.cs" /> <Compile Include="FileFormats\Format80.cs" />
<Compile Include="FileFormats\IniFile.cs" /> <Compile Include="FileFormats\IniFile.cs" />
<Compile Include="Graphics\Dune2ShpReader.cs" />
<Compile Include="Graphics\IGraphicsDevice.cs" /> <Compile Include="Graphics\IGraphicsDevice.cs" />
<Compile Include="Graphics\IInputHandler.cs" /> <Compile Include="Graphics\IInputHandler.cs" />
<Compile Include="Graphics\PngLoader.cs" /> <Compile Include="Graphics\PngLoader.cs" />
<Compile Include="Graphics\ShpReader.cs" /> <Compile Include="Graphics\ShpReader.cs" />
<Compile Include="Graphics\ShpWriter.cs" />
<Compile Include="Graphics\Vertex.cs" /> <Compile Include="Graphics\Vertex.cs" />
<Compile Include="Graphics\VqaReader.cs" /> <Compile Include="Graphics\VqaReader.cs" />
<Compile Include="InstallUtils.cs" /> <Compile Include="InstallUtils.cs" />
<Compile Include="Manifest.cs" /> <Compile Include="Manifest.cs" />
<Compile Include="Map\PlayerReference.cs" /> <Compile Include="Map\PlayerReference.cs" />
<Compile Include="Map\SmudgeReference.cs" /> <Compile Include="Map\SmudgeReference.cs" />
<Compile Include="Map\Terrain.cs" />
<Compile Include="Map\TileReference.cs" /> <Compile Include="Map\TileReference.cs" />
<Compile Include="Map\TileSet.cs" /> <Compile Include="Map\TileSet.cs" />
<Compile Include="MiniYaml.cs" /> <Compile Include="MiniYaml.cs" />
@@ -144,7 +141,6 @@
<Compile Include="StreamExts.cs" /> <Compile Include="StreamExts.cs" />
<Compile Include="FileFormats\WavLoader.cs" /> <Compile Include="FileFormats\WavLoader.cs" />
<Compile Include="Graphics\R8Reader.cs" /> <Compile Include="Graphics\R8Reader.cs" />
<Compile Include="Graphics\TileSetRenderer.cs" />
<Compile Include="Keycode.cs" /> <Compile Include="Keycode.cs" />
<Compile Include="Hotkey.cs" /> <Compile Include="Hotkey.cs" />
<Compile Include="FileSystem\FileSystem.cs" /> <Compile Include="FileSystem\FileSystem.cs" />
@@ -153,6 +149,10 @@
<Compile Include="FileSystem\MixFile.cs" /> <Compile Include="FileSystem\MixFile.cs" />
<Compile Include="FileSystem\ZipFile.cs" /> <Compile Include="FileSystem\ZipFile.cs" />
<Compile Include="FileSystem\D2kSoundResources.cs" /> <Compile Include="FileSystem\D2kSoundResources.cs" />
<Compile Include="Graphics\SpriteSource.cs" />
<Compile Include="Graphics\TmpRAReader.cs" />
<Compile Include="Graphics\TmpTDReader.cs" />
<Compile Include="Graphics\ShpD2Reader.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5"> <BootstrapperPackage Include="Microsoft.Net.Client.3.5">

View File

@@ -10,6 +10,7 @@
using System; using System;
using System.Drawing; using System.Drawing;
using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics; using OpenRA.FileFormats.Graphics;
namespace OpenRA.Graphics namespace OpenRA.Graphics
@@ -52,9 +53,14 @@ namespace OpenRA.Graphics
this.allocateSheet = allocateSheet; this.allocateSheet = allocateSheet;
} }
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, frame.Offset); }
public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); } public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); }
public Sprite Add(byte[] src, Size size, float2 spriteOffset) public Sprite Add(byte[] src, Size size, float2 spriteOffset)
{ {
// Don't bother allocating empty sprites
if (size.Width == 0 || size.Height == 0)
return new Sprite(current, Rectangle.Empty, spriteOffset, channel, BlendMode.Alpha);
var rect = Allocate(size, spriteOffset); var rect = Allocate(size, spriteOffset);
Util.FastCopyIntoChannel(rect, src); Util.FastCopyIntoChannel(rect, src);
current.CommitData(); current.CommitData();

View File

@@ -16,39 +16,25 @@ namespace OpenRA.Graphics
{ {
public class SpriteLoader public class SpriteLoader
{ {
public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
{
SheetBuilder = sheetBuilder;
this.exts = exts;
sprites = new Cache<string, Sprite[]>(LoadSprites);
}
readonly SheetBuilder SheetBuilder; readonly SheetBuilder SheetBuilder;
readonly Cache<string, Sprite[]> sprites; readonly Cache<string, Sprite[]> sprites;
readonly string[] exts; readonly string[] exts;
Sprite[] LoadSprites(string filename) public SpriteLoader(string[] exts, SheetBuilder sheetBuilder)
{ {
// TODO: Cleanly abstract file type detection SheetBuilder = sheetBuilder;
if (filename.ToLower().EndsWith("r8"))
{
var r8 = new R8Reader(FileSystem.Open(filename));
return r8.Select(a => SheetBuilder.Add(a.Image, a.Size, a.Offset)).ToArray();
}
BinaryReader reader = new BinaryReader(FileSystem.OpenWithExts(filename, exts)); // Include extension-less version
this.exts = exts.Append("").ToArray();
sprites = new Cache<string, Sprite[]>(CacheSpriteFrames);
}
var ImageCount = reader.ReadUInt16(); Sprite[] CacheSpriteFrames(string filename)
if (ImageCount == 0) {
{ var stream = FileSystem.OpenWithExts(filename, exts);
var shp = new ShpTSReader(FileSystem.OpenWithExts(filename, exts)); return SpriteSource.LoadSpriteSource(stream, filename).Frames
return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); .Select(a => SheetBuilder.Add(a))
} .ToArray();
else
{
var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts));
return shp.Frames.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray();
}
} }
public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; } public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; }

View File

@@ -11,6 +11,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
@@ -22,27 +23,31 @@ namespace OpenRA.Graphics
Dictionary<ushort, Sprite[]> templates; Dictionary<ushort, Sprite[]> templates;
Sprite missingTile; Sprite missingTile;
Sprite[] LoadTemplate(string filename, string[] exts, Cache<string, R8Reader> r8Cache, int[] frames) Sprite[] LoadTemplate(string filename, string[] exts, Dictionary<string, ISpriteSource> sourceCache, int[] frames)
{ {
if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8")) ISpriteSource source;
if (!sourceCache.ContainsKey(filename))
{ {
return frames.Select(f => using (var s = FileSystem.OpenWithExts(filename, exts))
{ source = SpriteSource.LoadSpriteSource(s, filename);
if (f < 0)
return null;
var image = r8Cache[filename][f]; if (source.CacheWhenLoadingTileset)
return sheetBuilder.Add(image.Image, new Size(image.Size.Width, image.Size.Height)); sourceCache.Add(filename, source);
}).ToArray(); }
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();
} }
using (var s = FileSystem.OpenWithExts(filename, exts)) return source.Frames.Select(f => sheetBuilder.Add(f)).ToArray();
{
var t = new Terrain(s);
return t.TileBitmapBytes
.Select(b => b != null ? sheetBuilder.Add(b, new Size(t.Width, t.Height)) : null)
.ToArray();
}
} }
public Theater(TileSet tileset) public Theater(TileSet tileset)
@@ -57,11 +62,11 @@ namespace OpenRA.Graphics
return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize));
}; };
var r8Cache = new Cache<string, R8Reader>(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); var sourceCache = new Dictionary<string, ISpriteSource>();
templates = new Dictionary<ushort, Sprite[]>(); templates = new Dictionary<ushort, Sprite[]>();
sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate);
foreach (var t in tileset.Templates) foreach (var t in tileset.Templates)
templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames));
// 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));
@@ -70,11 +75,13 @@ namespace OpenRA.Graphics
public Sprite TileSprite(TileReference<ushort, byte> r) public Sprite TileSprite(TileReference<ushort, byte> r)
{ {
Sprite[] template; Sprite[] template;
if (templates.TryGetValue(r.Type, out template)) if (!templates.TryGetValue(r.Type, out template))
if (template.Length > r.Index && template[r.Index] != null) return missingTile;
return template[r.Index];
return missingTile; if (r.Index >= template.Length)
return missingTile;
return template[r.Index];
} }
public Sheet Sheet { get { return sheetBuilder.Current; } } public Sheet Sheet { get { return sheetBuilder.Current; } }

View File

@@ -75,7 +75,7 @@ namespace OpenRA
ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeMetrics.Initialize(Manifest.ChromeMetrics);
ChromeProvider.Initialize(Manifest.Chrome); ChromeProvider.Initialize(Manifest.Chrome);
SheetBuilder = new SheetBuilder(SheetType.Indexed); SheetBuilder = new SheetBuilder(SheetType.Indexed);
SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder); SpriteLoader = new SpriteLoader(new string[0], SheetBuilder);
VoxelLoader = new VoxelLoader(); VoxelLoader = new VoxelLoader();
CursorProvider.Initialize(Manifest.Cursors); CursorProvider.Initialize(Manifest.Cursors);
} }

View File

@@ -56,6 +56,7 @@ namespace OpenRA.Widgets
Sprite sprite = null; Sprite sprite = null;
string cachedImage = null; string cachedImage = null;
int cachedFrame = -1; int cachedFrame = -1;
float2 cachedOffset = float2.Zero;
public override void Draw() public override void Draw()
{ {
@@ -68,9 +69,10 @@ namespace OpenRA.Widgets
sprite = Game.modData.SpriteLoader.LoadAllSprites(image)[frame]; sprite = Game.modData.SpriteLoader.LoadAllSprites(image)[frame];
cachedImage = image; cachedImage = image;
cachedFrame = frame; cachedFrame = frame;
cachedOffset = 0.5f * (new float2(RenderBounds.Size) - sprite.size);
} }
Game.Renderer.SpriteRenderer.DrawSprite(sprite, RenderOrigin, worldRenderer.Palette(palette)); Game.Renderer.SpriteRenderer.DrawSprite(sprite, RenderOrigin + cachedOffset, worldRenderer.Palette(palette));
} }
public int FrameCount public int FrameCount

View File

@@ -29,14 +29,14 @@ namespace OpenRA.Widgets
Game.Renderer.RgbaSpriteRenderer.DrawSprite(s,pos); Game.Renderer.RgbaSpriteRenderer.DrawSprite(s,pos);
} }
public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr) public static void DrawSHPCentered(Sprite s, float2 pos, WorldRenderer wr)
{ {
Game.Renderer.SpriteRenderer.DrawSprite(s, pos, wr.Palette("chrome")); Game.Renderer.SpriteRenderer.DrawSprite(s, pos - 0.5f * s.size, wr.Palette("chrome"));
} }
public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr, float2 size) public static void DrawSHPCentered(Sprite s, float2 pos, WorldRenderer wr, float scale)
{ {
Game.Renderer.SpriteRenderer.DrawSprite(s, pos, wr.Palette("chrome"), size); Game.Renderer.SpriteRenderer.DrawSprite(s, pos - 0.5f * scale * s.size, wr.Palette("chrome"), scale * s.size);
} }
public static void DrawPanel(string collection, Rectangle Bounds) public static void DrawPanel(string collection, Rectangle Bounds)

View File

@@ -197,11 +197,14 @@ namespace OpenRA.Mods.Cnc.Widgets
public override void Draw() public override void Draw()
{ {
var iconSize = new float2(64, 48);
var iconOffset = 0.5f * iconSize;
overlayFont = Game.Renderer.Fonts["TinyBold"]; overlayFont = Game.Renderer.Fonts["TinyBold"];
timeOffset = new float2(32, 24) - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2;
queuedOffset = new float2(4, 2); queuedOffset = new float2(4, 2);
holdOffset = new float2(32, 24) - overlayFont.Measure(HoldText) / 2; holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2;
readyOffset = new float2(32, 24) - overlayFont.Measure(ReadyText) / 2; readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2;
if (CurrentQueue == null) if (CurrentQueue == null)
return; return;
@@ -215,7 +218,7 @@ namespace OpenRA.Mods.Cnc.Widgets
// Icons // Icons
foreach (var icon in icons.Values) foreach (var icon in icons.Values)
{ {
WidgetUtils.DrawSHP(icon.Sprite, icon.Pos, worldRenderer); WidgetUtils.DrawSHPCentered(icon.Sprite, icon.Pos + iconOffset, worldRenderer);
// Build progress // Build progress
if (icon.Queued.Count > 0) if (icon.Queued.Count > 0)
@@ -225,10 +228,10 @@ namespace OpenRA.Mods.Cnc.Widgets
() => (first.TotalTime - first.RemainingTime) () => (first.TotalTime - first.RemainingTime)
* (clock.CurrentSequence.Length - 1) / first.TotalTime); * (clock.CurrentSequence.Length - 1) / first.TotalTime);
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, icon.Pos, worldRenderer); WidgetUtils.DrawSHPCentered(clock.Image, icon.Pos + iconOffset, worldRenderer);
} }
else if (!buildableItems.Any(a => a.Name == icon.Name)) else if (!buildableItems.Any(a => a.Name == icon.Name))
WidgetUtils.DrawSHP(cantBuild.Image, icon.Pos, worldRenderer); WidgetUtils.DrawSHPCentered(cantBuild.Image, icon.Pos + iconOffset, worldRenderer);
} }
// Overlays // Overlays

View File

@@ -89,10 +89,13 @@ namespace OpenRA.Mods.Cnc.Widgets
public override void Draw() public override void Draw()
{ {
var iconSize = new float2(64, 48);
var iconOffset = 0.5f * iconSize;
overlayFont = Game.Renderer.Fonts["TinyBold"]; overlayFont = Game.Renderer.Fonts["TinyBold"];
holdOffset = new float2(32, 24) - overlayFont.Measure(HoldText) / 2; holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2;
readyOffset = new float2(32, 24) - overlayFont.Measure(ReadyText) / 2; readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2;
timeOffset = new float2(32, 24) - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2;
// Background // Background
foreach (var rect in icons.Keys) foreach (var rect in icons.Keys)
@@ -101,14 +104,14 @@ namespace OpenRA.Mods.Cnc.Widgets
// Icons // Icons
foreach (var p in icons.Values) foreach (var p in icons.Values)
{ {
WidgetUtils.DrawSHP(p.Sprite, p.Pos, worldRenderer); WidgetUtils.DrawSHPCentered(p.Sprite, p.Pos + iconOffset, worldRenderer);
// Charge progress // Charge progress
clock.PlayFetchIndex("idle", clock.PlayFetchIndex("idle",
() => (p.Power.TotalTime - p.Power.RemainingTime) () => (p.Power.TotalTime - p.Power.RemainingTime)
* (clock.CurrentSequence.Length - 1) / p.Power.TotalTime); * (clock.CurrentSequence.Length - 1) / p.Power.TotalTime);
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, p.Pos, worldRenderer); WidgetUtils.DrawSHPCentered(clock.Image, p.Pos + iconOffset, worldRenderer);
} }
// Overlay // Overlay

View File

@@ -33,9 +33,9 @@
<BootstrapperEnabled>true</BootstrapperEnabled> <BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>True</DebugSymbols>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<Optimize>false</Optimize> <Optimize>False</Optimize>
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
@@ -47,17 +47,17 @@
</CustomCommands> </CustomCommands>
</CustomCommands> </CustomCommands>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
<Optimize>true</Optimize> <Optimize>True</Optimize>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="FuzzyLogicLibrary"> <Reference Include="FuzzyLogicLibrary">
@@ -70,14 +70,13 @@
<Reference Include="System.Data.DataSetExtensions" /> <Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\thirdparty\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="Mono.Nat"> <Reference Include="Mono.Nat">
<HintPath>..\thirdparty\Mono.Nat.dll</HintPath> <HintPath>..\thirdparty\Mono.Nat.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="ICSharpCode.SharpZipLib">
<HintPath>..\thirdparty\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Activities\CaptureActor.cs" /> <Compile Include="Activities\CaptureActor.cs" />
@@ -444,7 +443,6 @@
<Compile Include="Widgets\HueSliderWidget.cs" /> <Compile Include="Widgets\HueSliderWidget.cs" />
<Compile Include="Render\WithTurret.cs" /> <Compile Include="Render\WithTurret.cs" />
<Compile Include="Widgets\Logic\AssetBrowserLogic.cs" /> <Compile Include="Widgets\Logic\AssetBrowserLogic.cs" />
<Compile Include="Widgets\Logic\ConvertGameFilesLogic.cs" />
<Compile Include="VoxelNormalsPalette.cs" /> <Compile Include="VoxelNormalsPalette.cs" />
<Compile Include="Render\RenderVoxels.cs" /> <Compile Include="Render\RenderVoxels.cs" />
<Compile Include="Render\WithVoxelTurret.cs" /> <Compile Include="Render\WithVoxelTurret.cs" />
@@ -481,7 +479,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\LuaInterface\LuaInterface.csproj"> <ProjectReference Include="..\LuaInterface\LuaInterface.csproj">
<Project>{e915a0a4-2641-4f7e-8a88-8f123fa88bf1}</Project> <Project>{E915A0A4-2641-4F7E-8A88-8F123FA88BF1}</Project>
<Name>LuaInterface</Name> <Name>LuaInterface</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj"> <ProjectReference Include="..\OpenRA.FileFormats\OpenRA.FileFormats.csproj">
@@ -495,13 +493,9 @@
<Private>False</Private> <Private>False</Private>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\OpenRA.Irc\OpenRA.Irc.csproj"> <ProjectReference Include="..\OpenRA.Irc\OpenRA.Irc.csproj">
<Project>{85b48234-8b31-4be6-af9c-665cc6866841}</Project> <Project>{85B48234-8B31-4BE6-AF9C-665CC6866841}</Project>
<Name>OpenRA.Irc</Name> <Name>OpenRA.Irc</Name>
</ProjectReference> </ProjectReference>
<ProjectReference Include="..\OpenRA.Utility\OpenRA.Utility.csproj">
<Project>{F33337BE-CB69-4B24-850F-07D23E408DDF}</Project>
<Name>OpenRA.Utility</Name>
</ProjectReference>
<ProjectReference Include="..\GeoIP\GeoIP.csproj"> <ProjectReference Include="..\GeoIP\GeoIP.csproj">
<Project>{021DDD6A-A608-424C-9A9A-252D8A9989E0}</Project> <Project>{021DDD6A-A608-424C-9A9A-252D8A9989E0}</Project>
<Name>GeoIP</Name> <Name>GeoIP</Name>

View File

@@ -203,6 +203,7 @@ namespace OpenRA.Mods.RA.Widgets
string paletteCollection = "palette-" + world.LocalPlayer.Country.Race; string paletteCollection = "palette-" + world.LocalPlayer.Country.Race;
float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9);
var iconOffset = 0.5f * new float2(IconWidth, IconHeight);
var x = 0; var x = 0;
var y = 0; var y = 0;
@@ -233,7 +234,7 @@ namespace OpenRA.Mods.RA.Widgets
var drawPos = new float2(rect.Location); var drawPos = new float2(rect.Location);
var icon = new Animation(RenderSimple.GetImage(item)); var icon = new Animation(RenderSimple.GetImage(item));
icon.Play(item.Traits.Get<TooltipInfo>().Icon); icon.Play(item.Traits.Get<TooltipInfo>().Icon);
WidgetUtils.DrawSHP(icon.Image, drawPos, worldRenderer); WidgetUtils.DrawSHPCentered(icon.Image, drawPos + iconOffset, worldRenderer);
var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name);
@@ -248,7 +249,7 @@ namespace OpenRA.Mods.RA.Widgets
() => (firstOfThis.TotalTime - firstOfThis.RemainingTime) () => (firstOfThis.TotalTime - firstOfThis.RemainingTime)
* (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime); * (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime);
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); WidgetUtils.DrawSHPCentered(clock.Image, drawPos + iconOffset, worldRenderer);
if (queue.CurrentItem() == firstOfThis) if (queue.CurrentItem() == firstOfThis)
textBits.Add(Pair.New(overlayPos, GetOverlayForItem(firstOfThis))); textBits.Add(Pair.New(overlayPos, GetOverlayForItem(firstOfThis)));
@@ -269,7 +270,7 @@ namespace OpenRA.Mods.RA.Widgets
if (x != 0) y++; if (x != 0) y++;
foreach (var ob in overlayBits) foreach (var ob in overlayBits)
WidgetUtils.DrawSHP(ob.First, ob.Second, worldRenderer); WidgetUtils.DrawSHPCentered(ob.First, ob.Second + iconOffset, worldRenderer);
var font = Game.Renderer.Fonts["TinyBold"]; var font = Game.Renderer.Fonts["TinyBold"];
foreach (var tb in textBits) foreach (var tb in textBits)

View File

@@ -35,6 +35,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
PaletteFromFile currentPalette; PaletteFromFile currentPalette;
static readonly string[] AllowedExtensions = { ".shp", ".r8", ".tem", ".des", ".sno", ".int" };
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public AssetBrowserLogic(Widget widget, Action onExit, World world) public AssetBrowserLogic(Widget widget, Action onExit, World world)
{ {
@@ -60,6 +62,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var paletteDropDown = panel.Get<DropDownButtonWidget>("PALETTE_SELECTOR"); var paletteDropDown = panel.Get<DropDownButtonWidget>("PALETTE_SELECTOR");
paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world); paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world);
paletteDropDown.GetText = () => currentPalette.Name;
var colorPreview = panel.Get<ColorPreviewManagerWidget>("COLOR_MANAGER"); var colorPreview = panel.Get<ColorPreviewManagerWidget>("COLOR_MANAGER");
colorPreview.Color = Game.Settings.Player.Color; colorPreview.Color = Game.Settings.Player.Color;
@@ -80,7 +83,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
frameSlider.OnChange += x => { spriteWidget.Frame = (int)Math.Round(x); }; frameSlider.OnChange += x => { spriteWidget.Frame = (int)Math.Round(x); };
frameSlider.GetValue = () => spriteWidget.Frame; frameSlider.GetValue = () => spriteWidget.Frame;
panel.Get<LabelWidget>("FRAME_COUNT").GetText = () => "{0}/{1}".F(spriteWidget.Frame, spriteWidget.FrameCount); panel.Get<LabelWidget>("FRAME_COUNT").GetText = () => "{0} / {1}".F(spriteWidget.Frame + 1, spriteWidget.FrameCount + 1);
playButton = panel.Get<ButtonWidget>("BUTTON_PLAY"); playButton = panel.Get<ButtonWidget>("BUTTON_PLAY");
playButton.OnClick = () => playButton.OnClick = () =>
@@ -118,96 +121,15 @@ namespace OpenRA.Mods.RA.Widgets.Logic
template = panel.Get<ScrollItemWidget>("ASSET_TEMPLATE"); template = panel.Get<ScrollItemWidget>("ASSET_TEMPLATE");
PopulateAssetList(); PopulateAssetList();
var modID = Game.modData.Manifest.Mod.Id;
// TODO: This should not invoke the OpenRA.Utility.exe, but use it's functions directly.
// TODO: Does not work with SHP(TS) yet?!
panel.Get<ButtonWidget>("EXPORT_BUTTON").OnClick = () =>
{
var ExtractGameFiles = new string[][]
{
new string[] { "--extract", modID, currentPalette.Filename, "--userdir" },
new string[] { "--extract", modID, "{0}.shp".F(spriteWidget.Image), "--userdir" },
};
var ExportToPng = new string[][]
{
new string[] { "--png", Platform.SupportDir + "{0}.shp".F(spriteWidget.Image), Platform.SupportDir + currentPalette.Filename },
};
var ImportFromPng = new string[][] { };
var args = new WidgetArgs()
{
{ "ExtractGameFiles", ExtractGameFiles },
{ "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng }
};
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
};
panel.Get<ButtonWidget>("EXTRACT_BUTTON").OnClick = () =>
{
var ExtractGameFilesList = new List<string[]>();
var ExportToPngList = new List<string[]>();
ExtractGameFilesList.Add(new string[] { "--extract", modID, currentPalette.Filename, "--userdir" });
foreach (var shp in availableShps)
{
ExtractGameFilesList.Add(new string[] { "--extract", modID, shp, "--userdir" });
ExportToPngList.Add(new string[] { "--png", Platform.SupportDir + shp, Platform.SupportDir + currentPalette.Filename });
Console.WriteLine(Platform.SupportDir + shp);
}
var ExtractGameFiles = ExtractGameFilesList.ToArray();
var ExportToPng = ExportToPngList.ToArray();
var ImportFromPng = new string[][] { };
var args = new WidgetArgs()
{
{ "ExtractGameFiles", ExtractGameFiles },
{ "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng }
};
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
};
panel.Get<ButtonWidget>("IMPORT_BUTTON").OnClick = () =>
{
var imageSizeInput = panel.Get<TextFieldWidget>("IMAGE_SIZE_INPUT");
var imageFilename = panel.Get<TextFieldWidget>("IMAGE_FILENAME_INPUT");
var ExtractGameFiles = new string[][] { };
var ExportToPng = new string[][] { };
var ImportFromPng = new string[][]
{
new string[] { "--shp", Platform.SupportDir + imageFilename.Text, imageSizeInput.Text },
};
var args = new WidgetArgs()
{
{ "ExtractGameFiles", ExtractGameFiles },
{ "ExportToPng", ExportToPng },
{ "ImportFromPng", ImportFromPng }
};
Ui.OpenWindow("CONVERT_ASSETS_PANEL", args);
};
panel.Get<ButtonWidget>("CLOSE_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; panel.Get<ButtonWidget>("CLOSE_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); };
} }
void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template) void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template)
{ {
var r8 = filepath.EndsWith(".r8", true, CultureInfo.InvariantCulture); var filename = Path.GetFileName(filepath);
var filename = Path.GetFileName(filepath);
var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filepath);
var item = ScrollItemWidget.Setup(template, var item = ScrollItemWidget.Setup(template,
() => spriteWidget.Image == sprite, () => spriteWidget.Image == filename,
() => {filenameInput.Text = filename; LoadAsset(filename); }); () => { filenameInput.Text = filename; LoadAsset(filename); });
item.Get<LabelWidget>("TITLE").GetText = () => filepath; item.Get<LabelWidget>("TITLE").GetText = () => filepath;
list.AddChild(item); list.AddChild(item);
@@ -221,11 +143,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
if (!FileSystem.Exists(filename)) if (!FileSystem.Exists(filename))
return false; return false;
var r8 = filename.EndsWith(".r8", true, CultureInfo.InvariantCulture);
var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filename);
spriteWidget.Frame = 0; spriteWidget.Frame = 0;
spriteWidget.Image = sprite; spriteWidget.Image = filename;
frameSlider.MaximumValue = (float)spriteWidget.FrameCount; frameSlider.MaximumValue = (float)spriteWidget.FrameCount;
frameSlider.Ticks = spriteWidget.FrameCount + 1; frameSlider.Ticks = spriteWidget.FrameCount + 1;
return true; return true;
@@ -265,7 +184,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var files = assetSource.AllFileNames(); var files = assetSource.AllFileNames();
foreach (var file in files) foreach (var file in files)
{ {
if (file.EndsWith(".shp", true, CultureInfo.InvariantCulture) || file.EndsWith(".r8", true, CultureInfo.InvariantCulture)) if (AllowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture)))
{ {
AddAsset(assetList, file, template); AddAsset(assetList, file, template);
availableShps.Add(file); availableShps.Add(file);
@@ -278,8 +197,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
Func<PaletteFromFile, ScrollItemWidget, ScrollItemWidget> setupItem = (palette, itemTemplate) => Func<PaletteFromFile, ScrollItemWidget, ScrollItemWidget> setupItem = (palette, itemTemplate) =>
{ {
var item = ScrollItemWidget.Setup(itemTemplate, var item = ScrollItemWidget.Setup(itemTemplate,
() => currentPalette.Name == palette.Name, () => currentPalette.Name == palette.Name,
() => { currentPalette = palette; spriteWidget.Palette = currentPalette.Name; }); () => { currentPalette = palette; spriteWidget.Palette = currentPalette.Name; });
item.Get<LabelWidget>("LABEL").GetText = () => palette.Name; item.Get<LabelWidget>("LABEL").GetText = () => palette.Name;
return item; return item;
}; };

View File

@@ -1,110 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 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.IO;
using System.Linq;
using System.Threading;
using OpenRA.Utility;
using OpenRA.Widgets;
namespace OpenRA.Mods.RA.Widgets.Logic
{
public class ConvertGameFilesLogic
{
Widget panel;
ProgressBarWidget progressBar;
LabelWidget statusLabel;
ButtonWidget retryButton, backButton;
Widget extractingContainer;
string[][] ExtractGameFiles, ExportToPng, ImportFromPng;
[ObjectCreator.UseCtor]
public ConvertGameFilesLogic(Widget widget, string[][] ExtractGameFiles, string[][] ExportToPng, string[][] ImportFromPng)
{
panel = widget.Get("CONVERT_ASSETS_PANEL");
progressBar = panel.Get<ProgressBarWidget>("PROGRESS_BAR");
statusLabel = panel.Get<LabelWidget>("STATUS_LABEL");
backButton = panel.Get<ButtonWidget>("BACK_BUTTON");
backButton.OnClick = Ui.CloseWindow;
retryButton = panel.Get<ButtonWidget>("RETRY_BUTTON");
retryButton.OnClick = Extract;
extractingContainer = panel.Get("EXTRACTING");
this.ExtractGameFiles = ExtractGameFiles;
this.ExportToPng = ExportToPng;
this.ImportFromPng = ImportFromPng;
Extract();
}
void Extract()
{
backButton.IsDisabled = () => true;
retryButton.IsDisabled = () => true;
extractingContainer.IsVisible = () => true;
var onError = (Action<string>)(s => Game.RunAfterTick(() =>
{
statusLabel.GetText = () => "Error: "+s;
backButton.IsDisabled = () => false;
retryButton.IsDisabled = () => false;
}));
var t = new Thread( _ =>
{
try
{
for (int i = 0; i < ExtractGameFiles.Length; i++)
{
progressBar.Percentage = i*100/ExtractGameFiles.Count();
statusLabel.GetText = () => "Extracting...";
Command.ExtractFiles(ExtractGameFiles[i]);
}
for (int i = 0; i < ExportToPng.Length; i++)
{
progressBar.Percentage = i*100/ExportToPng.Count();
statusLabel.GetText = () => "Exporting SHP to PNG...";
Command.ConvertShpToPng(ExportToPng[i]);
}
for (int i = 0; i < ImportFromPng.Length; i++)
{
progressBar.Percentage = i*100/ImportFromPng.Count();
statusLabel.GetText = () => "Converting PNG to SHP...";
Command.ConvertPngToShp(ImportFromPng[i]);
}
Game.RunAfterTick(() =>
{
progressBar.Percentage = 100;
statusLabel.GetText = () => "Done. Check {0}".F(Platform.SupportDir);
backButton.IsDisabled = () => false;
});
}
catch (FileNotFoundException f)
{
onError(f.FileName+" not found.");
}
catch (Exception e)
{
onError(e.Message);
}
}) { IsBackground = true };
t.Start();
}
}
}

View File

@@ -25,6 +25,10 @@ namespace OpenRA.Mods.RA.Widgets
WorldRenderer worldRenderer; WorldRenderer worldRenderer;
Dictionary<ProductionQueue, Animation> clocks; Dictionary<ProductionQueue, Animation> clocks;
public int IconWidth = 32;
public int IconHeight = 24;
public int IconSpacing = 8;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public ObserverProductionIconsWidget(World world, WorldRenderer worldRenderer) public ObserverProductionIconsWidget(World world, WorldRenderer worldRenderer)
{ {
@@ -59,6 +63,8 @@ namespace OpenRA.Mods.RA.Widgets
clocks.Add(queue.Trait, new Animation("clock")); clocks.Add(queue.Trait, new Animation("clock"));
} }
} }
var iconSize = new float2(IconWidth, IconHeight);
foreach (var queue in queues) foreach (var queue in queues)
{ {
var current = queue.Trait.CurrentItem(); var current = queue.Trait.CurrentItem();
@@ -71,16 +77,15 @@ namespace OpenRA.Mods.RA.Widgets
var icon = new Animation(RenderSimple.GetImage(actor)); var icon = new Animation(RenderSimple.GetImage(actor));
icon.Play(actor.Traits.Get<TooltipInfo>().Icon); icon.Play(actor.Traits.Get<TooltipInfo>().Icon);
var size = icon.Image.size / new float2(2, 2); var location = new float2(RenderBounds.Location) + new float2(queue.i * (IconWidth + IconSpacing), 0);
var location = new float2(RenderBounds.Location) + new float2(queue.i * (int)size.Length, 0); WidgetUtils.DrawSHPCentered(icon.Image, location + 0.5f * iconSize, worldRenderer, 0.5f);
WidgetUtils.DrawSHP(icon.Image, location, worldRenderer, size);
var clock = clocks[queue.Trait]; var clock = clocks[queue.Trait];
clock.PlayFetchIndex("idle", clock.PlayFetchIndex("idle",
() => current.TotalTime == 0 ? 0 : ((current.TotalTime - current.RemainingTime) () => current.TotalTime == 0 ? 0 : ((current.TotalTime - current.RemainingTime)
* (clock.CurrentSequence.Length - 1) / current.TotalTime)); * (clock.CurrentSequence.Length - 1) / current.TotalTime));
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, location, worldRenderer, size); WidgetUtils.DrawSHPCentered(clock.Image, location + 0.5f * iconSize, worldRenderer, 0.5f);
var tiny = Game.Renderer.Fonts["Tiny"]; var tiny = Game.Renderer.Fonts["Tiny"];
var text = GetOverlayForItem(current); var text = GetOverlayForItem(current);

View File

@@ -25,6 +25,10 @@ namespace OpenRA.Mods.RA.Widgets
WorldRenderer worldRenderer; WorldRenderer worldRenderer;
Dictionary<string, Animation> clocks; Dictionary<string, Animation> clocks;
public int IconWidth = 32;
public int IconHeight = 24;
public int IconSpacing = 8;
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
public ObserverSupportPowerIconsWidget(World world, WorldRenderer worldRenderer) public ObserverSupportPowerIconsWidget(World world, WorldRenderer worldRenderer)
{ {
@@ -61,22 +65,24 @@ namespace OpenRA.Mods.RA.Widgets
clocks.Add(power.a.Key, new Animation("clock")); clocks.Add(power.a.Key, new Animation("clock"));
} }
} }
var iconSize = new float2(IconWidth, IconHeight);
foreach (var power in powers) foreach (var power in powers)
{ {
var item = power.a.Value; var item = power.a.Value;
if (item == null || item.Info == null || item.Info.Icon == null) if (item == null || item.Info == null || item.Info.Icon == null)
continue; continue;
icon.Play(item.Info.Icon); icon.Play(item.Info.Icon);
var size = icon.Image.size / new float2(2, 2); var location = new float2(RenderBounds.Location) + new float2(power.i * (IconWidth + IconSpacing), 0);
var location = new float2(RenderBounds.Location) + new float2(power.i * (int)size.Length, 0); WidgetUtils.DrawSHPCentered(icon.Image, location + 0.5f * iconSize, worldRenderer, 0.5f);
WidgetUtils.DrawSHP(icon.Image, location, worldRenderer, size);
var clock = clocks[power.a.Key]; var clock = clocks[power.a.Key];
clock.PlayFetchIndex("idle", clock.PlayFetchIndex("idle",
() => item.TotalTime == 0 ? 0 : ((item.TotalTime - item.RemainingTime) () => item.TotalTime == 0 ? 0 : ((item.TotalTime - item.RemainingTime)
* (clock.CurrentSequence.Length - 1) / item.TotalTime)); * (clock.CurrentSequence.Length - 1) / item.TotalTime));
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, location, worldRenderer, size); WidgetUtils.DrawSHPCentered(clock.Image, location + 0.5f * iconSize, worldRenderer, 0.5f);
var tiny = Game.Renderer.Fonts["Tiny"]; var tiny = Game.Renderer.Fonts["Tiny"];
var text = GetOverlayForItem(item); var text = GetOverlayForItem(item);

View File

@@ -23,6 +23,9 @@ namespace OpenRA.Mods.RA.Widgets
[Translate] public string ReadyText = ""; [Translate] public string ReadyText = "";
[Translate] public string HoldText = ""; [Translate] public string HoldText = "";
public int IconWidth = 64;
public int IconHeight = 48;
Animation icon; Animation icon;
Animation clock; Animation clock;
readonly List<Pair<Rectangle, Action<MouseInput>>> buttons = new List<Pair<Rectangle,Action<MouseInput>>>(); readonly List<Pair<Rectangle, Action<MouseInput>>> buttons = new List<Pair<Rectangle,Action<MouseInput>>>();
@@ -84,10 +87,11 @@ namespace OpenRA.Mods.RA.Widgets
WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51)); WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51));
// HACK: Hack Hack Hack // HACK: Hack Hack Hack
rectBounds.Width = 69; rectBounds.Width = IconWidth + 5;
rectBounds.Height = 10 + numPowers * 51 + 21; rectBounds.Height = 31 + numPowers * (IconHeight + 3);
var y = rectBounds.Y + 10; var y = rectBounds.Y + 10;
var iconSize = new float2(IconWidth, IconHeight);
foreach (var kv in powers) foreach (var kv in powers)
{ {
var sp = kv.Value; var sp = kv.Value;
@@ -137,14 +141,14 @@ namespace OpenRA.Mods.RA.Widgets
} }
} }
WidgetUtils.DrawSHP(icon.Image, drawPos, worldRenderer); WidgetUtils.DrawSHPCentered(icon.Image, drawPos + 0.5f * iconSize, worldRenderer);
clock.PlayFetchIndex("idle", clock.PlayFetchIndex("idle",
() => sp.TotalTime == 0 ? clock.CurrentSequence.Length - 1 : (sp.TotalTime - sp.RemainingTime) () => sp.TotalTime == 0 ? clock.CurrentSequence.Length - 1 : (sp.TotalTime - sp.RemainingTime)
* (clock.CurrentSequence.Length - 1) / sp.TotalTime); * (clock.CurrentSequence.Length - 1) / sp.TotalTime);
clock.Tick(); clock.Tick();
WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); WidgetUtils.DrawSHPCentered(clock.Image, drawPos + 0.5f * iconSize, worldRenderer);
var overlay = sp.Ready ? ReadyText : sp.Active ? null : HoldText; var overlay = sp.Ready ? ReadyText : sp.Active ? null : HoldText;
var font = Game.Renderer.Fonts["TinyBold"]; var font = Game.Renderer.Fonts["TinyBold"];

View File

@@ -19,6 +19,7 @@ using System.Runtime.InteropServices;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.FileFormats.Graphics; using OpenRA.FileFormats.Graphics;
using OpenRA.GameRules; using OpenRA.GameRules;
using OpenRA.Graphics;
using OpenRA.Traits; using OpenRA.Traits;
namespace OpenRA.Utility namespace OpenRA.Utility
@@ -42,46 +43,37 @@ namespace OpenRA.Utility
public static void ConvertPngToShp(string[] args) public static void ConvertPngToShp(string[] args)
{ {
var src = args[1]; var dest = args[1].Split('-').First() + ".shp";
var dest = Path.ChangeExtension(src, ".shp"); var frames = args.Skip(1).Select(a => PngLoader.Load(a));
var width = int.Parse(args[2]);
var srcImage = PngLoader.Load(src); var size = frames.First().Size;
if (frames.Any(f => f.Size != size))
if (srcImage.Width % width != 0) throw new InvalidOperationException("All frames must be the same size");
throw new InvalidOperationException("Bogus width; not a whole number of frames");
using (var destStream = File.Create(dest)) using (var destStream = File.Create(dest))
ShpWriter.Write(destStream, width, srcImage.Height, ShpReader.Write(destStream, size, frames.Select(f => f.ToBytes()));
srcImage.ToFrames(width));
Console.WriteLine(dest + " saved."); Console.WriteLine(dest + " saved.");
} }
static IEnumerable<byte[]> ToFrames(this Bitmap bitmap, int width) static byte[] ToBytes(this Bitmap bitmap)
{ {
for (var x = 0; x < bitmap.Width; x += width) var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly,
{ PixelFormat.Format8bppIndexed);
var data = bitmap.LockBits(new Rectangle(x, 0, width, bitmap.Height), ImageLockMode.ReadOnly,
PixelFormat.Format8bppIndexed);
var bytes = new byte[width * bitmap.Height]; var bytes = new byte[bitmap.Width * bitmap.Height];
for (var i = 0; i < bitmap.Height; i++) for (var i = 0; i < bitmap.Height; i++)
Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + i * data.Stride), Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + i * data.Stride),
bytes, i * width, width); bytes, i * bitmap.Width, bitmap.Width);
bitmap.UnlockBits(data); bitmap.UnlockBits(data);
yield return bytes; return bytes;
}
} }
public static void ConvertShpToPng(string[] args) public static void ConvertShpToPng(string[] args)
{ {
var src = args[1]; var src = args[1];
var dest = Path.ChangeExtension(src, ".png");
var srcImage = ShpReader.Load(src);
var shadowIndex = new int[] { }; var shadowIndex = new int[] { };
if (args.Contains("--noshadow")) if (args.Contains("--noshadow"))
{ {
@@ -93,134 +85,55 @@ namespace OpenRA.Utility
var palette = Palette.Load(args[2], shadowIndex); var palette = Palette.Load(args[2], shadowIndex);
using (var bitmap = new Bitmap(srcImage.ImageCount * srcImage.Width, srcImage.Height, PixelFormat.Format8bppIndexed)) ISpriteSource source;
using (var stream = File.OpenRead(src))
source = SpriteSource.LoadSpriteSource(stream, src);
// The r8 padding requires external information that we can't access here.
var usePadding = !(args.Contains("--nopadding") || source is R8Reader);
var count = 0;
var prefix = Path.GetFileNameWithoutExtension(src);
foreach (var frame in source.Frames)
{ {
var x = 0; var frameSize = usePadding ? frame.FrameSize : frame.Size;
bitmap.Palette = palette.AsSystemPalette(); var offset = usePadding ? (frame.Offset - 0.5f * new float2(frame.Size - frame.FrameSize)).ToInt2() : int2.Zero;
foreach (var frame in srcImage.Frames) // shp(ts) may define empty frames
if (frameSize.Width == 0 && frameSize.Height == 0)
{ {
var data = bitmap.LockBits(new Rectangle(x, 0, srcImage.Width, srcImage.Height), ImageLockMode.WriteOnly, count++;
PixelFormat.Format8bppIndexed); continue;
}
for (var i = 0; i < bitmap.Height; i++) using (var bitmap = new Bitmap(frameSize.Width, frameSize.Height, PixelFormat.Format8bppIndexed))
Marshal.Copy(frame.Image, i * srcImage.Width, {
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), srcImage.Width); bitmap.Palette = palette.AsSystemPalette();
var data = bitmap.LockBits(new Rectangle(0, 0, frameSize.Width, frameSize.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
x += srcImage.Width; // Clear the frame
if (usePadding)
{
var clearRow = new byte[data.Stride];
for (var i = 0; i < frameSize.Height; i++)
Marshal.Copy(clearRow, 0, new IntPtr(data.Scan0.ToInt64() + i * data.Stride), data.Stride);
}
for (var i = 0; i < frame.Size.Height; i++)
{
var destIndex = new IntPtr(data.Scan0.ToInt64() + (i + offset.Y) * data.Stride + offset.X);
Marshal.Copy(frame.Data, i * frame.Size.Width, destIndex, frame.Size.Width);
}
bitmap.UnlockBits(data); bitmap.UnlockBits(data);
var filename = "{0}-{1:D4}.png".F(prefix, count++);
bitmap.Save(filename);
} }
bitmap.Save(dest);
Console.WriteLine(dest + " saved");
}
}
public static void ConvertR8ToPng(string[] args)
{
var srcImage = new R8Reader(File.OpenRead(args[1]));
var shadowIndex = new int[] { };
if (args.Contains("--noshadow"))
{
Array.Resize(ref shadowIndex, shadowIndex.Length + 1);
shadowIndex[shadowIndex.Length - 1] = 3;
} }
var palette = Palette.Load(args[2], shadowIndex); Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1);
var startFrame = int.Parse(args[3]);
var endFrame = int.Parse(args[4]) + 1;
var filename = args[5];
var frameCount = endFrame - startFrame;
var frame = srcImage[startFrame];
var bitmap = new Bitmap(frame.FrameSize.Width * frameCount, frame.FrameSize.Height, PixelFormat.Format8bppIndexed);
bitmap.Palette = palette.AsSystemPalette();
frame = srcImage[startFrame];
if (args.Contains("--tileset"))
{
int f = 0;
var tileset = new Bitmap(frame.FrameSize.Width * 20, frame.FrameSize.Height * 40, PixelFormat.Format8bppIndexed);
tileset.Palette = palette.AsSystemPalette();
for (int h = 0; h < 40; h++)
{
for (int w = 0; w < 20; w++)
{
if (h * 20 + w < frameCount)
{
Console.WriteLine(f);
frame = srcImage[f];
var data = tileset.LockBits(new Rectangle(w * frame.Size.Width, h * frame.Size.Height, frame.Size.Width, frame.Size.Height),
ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);
for (var i = 0; i < frame.Size.Height; i++)
Marshal.Copy(frame.Image, i * frame.Size.Width,
new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width);
tileset.UnlockBits(data);
f++;
}
}
}
bitmap = tileset;
}
bitmap.Save(filename + ".png");
Console.WriteLine(filename + ".png saved");
}
public static void ConvertTmpToPng(string[] args)
{
var mod = args[1];
var theater = args[2];
var templateNames = args.Skip(3);
var shadowIndex = new int[] { 3, 4 };
var manifest = new Manifest(mod);
FileSystem.LoadFromManifest(manifest);
var tileset = manifest.TileSets.Select(a => new TileSet(a))
.FirstOrDefault(ts => ts.Name == theater);
if (tileset == null)
throw new InvalidOperationException("No theater named '{0}'".F(theater));
var renderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize));
var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex);
foreach (var templateName in templateNames)
{
var template = tileset.Templates.FirstOrDefault(tt => tt.Value.Image == templateName);
if (template.Value == null)
throw new InvalidOperationException("No such template '{0}'".F(templateName));
using (var image = renderer.RenderTemplate(template.Value.Id, palette))
image.Save(Path.ChangeExtension(templateName, ".png"));
}
}
public static void ConvertFormat2ToFormat80(string[] args)
{
var src = args[1];
var dest = args[2];
Dune2ShpReader srcImage = null;
using (var s = File.OpenRead(src))
srcImage = new Dune2ShpReader(s);
var size = srcImage.First().Size;
if (!srcImage.All(im => im.Size == size))
throw new InvalidOperationException("All the frames must be the same size to convert from Dune2 to RA");
using (var destStream = File.Create(dest))
ShpWriter.Write(destStream, size.Width, size.Height,
srcImage.Select(im => im.Image));
} }
public static void ExtractFiles(string[] args) public static void ExtractFiles(string[] args)
@@ -233,16 +146,12 @@ namespace OpenRA.Utility
foreach (var f in files) foreach (var f in files)
{ {
if (f == "--userdir")
break;
var src = FileSystem.Open(f); var src = FileSystem.Open(f);
if (src == null) if (src == null)
throw new InvalidOperationException("File not found: {0}".F(f)); throw new InvalidOperationException("File not found: {0}".F(f));
var data = src.ReadAllBytes(); var data = src.ReadAllBytes();
var output = args.Contains("--userdir") ? Platform.SupportDir + f : f; File.WriteAllBytes(f, data);
File.WriteAllBytes(output, data); Console.WriteLine(f + " saved.");
Console.WriteLine(output + " saved.");
} }
} }
@@ -300,8 +209,8 @@ namespace OpenRA.Utility
var srcImage = ShpReader.Load(args[3]); var srcImage = ShpReader.Load(args[3]);
using (var destStream = File.Create(args[4])) using (var destStream = File.Create(args[4]))
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height, ShpReader.Write(destStream, srcImage.Size,
srcImage.Frames.Select(im => im.Image.Select(px => (byte)remap[px]).ToArray())); srcImage.Frames.Select(im => im.Data.Select(px => (byte)remap[px]).ToArray()));
} }
public static void TransposeShp(string[] args) public static void TransposeShp(string[] args)
@@ -323,8 +232,7 @@ namespace OpenRA.Utility
} }
using (var destStream = File.Create(args[2])) using (var destStream = File.Create(args[2]))
ShpWriter.Write(destStream, srcImage.Width, srcImage.Height, ShpReader.Write(destStream, srcImage.Size, destFrames.Select(f => f.Data));
destFrames.Select(f => f.Image));
} }
static string FriendlyTypeName(Type t) static string FriendlyTypeName(Type t)

View File

@@ -23,11 +23,8 @@ namespace OpenRA.Utility
{ "--settings-value", Command.Settings }, { "--settings-value", Command.Settings },
{ "--shp", Command.ConvertPngToShp }, { "--shp", Command.ConvertPngToShp },
{ "--png", Command.ConvertShpToPng }, { "--png", Command.ConvertShpToPng },
{ "--fromd2", Command.ConvertFormat2ToFormat80 },
{ "--extract", Command.ExtractFiles }, { "--extract", Command.ExtractFiles },
{ "--tmp-png", Command.ConvertTmpToPng },
{ "--remap", Command.RemapShp }, { "--remap", Command.RemapShp },
{ "--r8", Command.ConvertR8ToPng },
{ "--transpose", Command.TransposeShp }, { "--transpose", Command.TransposeShp },
{ "--docs", Command.ExtractTraitDocs }, { "--docs", Command.ExtractTraitDocs },
{ "--map-hash", Command.GetMapHash }, { "--map-hash", Command.GetMapHash },
@@ -58,13 +55,10 @@ namespace OpenRA.Utility
Console.WriteLine("Usage: OpenRA.Utility.exe [OPTION] [ARGS]"); Console.WriteLine("Usage: OpenRA.Utility.exe [OPTION] [ARGS]");
Console.WriteLine(); Console.WriteLine();
Console.WriteLine(" --settings-value KEY Get value of KEY from settings.yaml"); Console.WriteLine(" --settings-value KEY Get value of KEY from settings.yaml");
Console.WriteLine(" --shp PNGFILE FRAMEWIDTH Convert a single PNG with multiple frames appended after another to a SHP"); Console.WriteLine(" --shp PNGFILE [PNGFILE ...] Combine a list of PNG images into a SHP");
Console.WriteLine(" --png SHPFILE PALETTE [--noshadow] Convert a SHP to a PNG containing all of its frames, optionally removing the shadow"); Console.WriteLine(" --png SPRITEFILE PALETTE [--noshadow] [--nopadding] Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow");
Console.WriteLine(" --fromd2 DUNE2SHP C&CSHP Convert a Dune II SHP (C&C mouse cursor) to C&C SHP format."); Console.WriteLine(" --extract MOD[,MOD]* FILES Extract files from mod packages to the current directory");
Console.WriteLine(" --extract MOD[,MOD]* FILES [--userdir] Extract files from mod packages to the current (or user) directory");
Console.WriteLine(" --tmp-png MOD[,MOD]* THEATER FILES Extract terrain tiles to PNG");
Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette"); Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette");
Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--noshadow] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type to append multiple frames to one PNG named by filename optionally removing the shadow.");
Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START."); Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START.");
Console.WriteLine(" --docs MOD Generate trait documentation in MarkDown format."); Console.WriteLine(" --docs MOD Generate trait documentation in MarkDown format.");
Console.WriteLine(" --map-hash MAPFILE Generate hash of specified oramap file."); Console.WriteLine(" --map-hash MAPFILE Generate hash of specified oramap file.");

View File

@@ -30,8 +30,10 @@ Background@COLOR_CHOOSER:
Width:144 Width:144
Height:72 Height:72
ShpImage@FACT: ShpImage@FACT:
X:160 X:153
Y:13 Y:1
Width:80
Height:73
Image:fact Image:fact
Palette:colorpicker Palette:colorpicker
Button@RANDOM_BUTTON: Button@RANDOM_BUTTON:

View File

@@ -4,7 +4,7 @@
Cursors: Cursors:
mouse2: cursor mouse2.shp: cursor
scroll-t: scroll-t:
start:1 start:1
scroll-tr: scroll-tr:
@@ -114,7 +114,7 @@ Cursors:
start:154 start:154
length:24 length:24
mouse4:cursor mouse4.shp:cursor
move: move:
start:0 start:0
length:8 length:8
@@ -125,7 +125,7 @@ Cursors:
start:0 start:0
length: 8 length: 8
attackmove:cursor attackmove.shp:cursor
attackmove: attackmove:
start:0 start:0
length:8 length:8
@@ -138,7 +138,7 @@ Cursors:
start:13 start:13
length:1 length:1
mouse3: cursor2 mouse3.shp: cursor2
enter-blocked: enter-blocked:
start:212 start:212
length:1 length:1
@@ -170,7 +170,7 @@ Cursors:
start:213 start:213
length:1 length:1
nopower: cursor nopower.shp: cursor
powerdown-blocked: powerdown-blocked:
start:0 start:0
length: 1 length: 1

View File

@@ -1,215 +0,0 @@
Background@ASSETBROWSER_BG:
Logic:AssetBrowserLogic
X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:700
Height:410
Children:
ColorPreviewManager@COLOR_MANAGER:
Label@ASSETBROWSER_TITLE:
X:0
Y:10
Width:PARENT_RIGHT
Height:25
Text:Game Asset Viewer & Converter
Align:Center
Font:Bold
DropDownButton@SOURCE_SELECTOR:
X:40
Y:45
Width:160
Height:25
Font:Bold
Text:Folders
ScrollPanel@ASSET_LIST:
X:40
Y:80
Width:160
Height:190
Children:
ScrollItem@ASSET_TEMPLATE:
Width:PARENT_RIGHT-27
Height:25
X:2
Y:0
Visible:false
Children:
Label@TITLE:
X:10
Width:PARENT_RIGHT-20
Height:25
TextField@FILENAME_INPUT:
X:40
Y:280
Width:140
Height:25
Text:mouse.r8
Button@LOAD_BUTTON:
X:40
Y:310
Width:140
Height:25
Text:Load
Font:Bold
Key:return
DropDownButton@PALETTE_SELECTOR:
X:230
Y:45
Width:150
Height:25
Font:Bold
Text:Palette
DropDownButton@COLOR:
X:380
Y:45
Width:80
Height:25
Children:
ColorBlock@COLORBLOCK:
X:5
Y:6
Width:PARENT_RIGHT-35
Height:PARENT_BOTTOM-12
Background@SPRITE_BG:
X:220
Y:80
Width:250
Height:250
Background:dialog4
Children:
ShpImage@SPRITE:
X:4
Y:4
Width:246
Height:246
Image:mouse.r8
Label@ACTIONS_TITLE:
X:PARENT_RIGHT - 150
Y:45
Width:PARENT_RIGHT
Height:25
Text:Actions
Font:Bold
Button@EXPORT_BUTTON:
X:PARENT_RIGHT - 200
Y:80
Width:160
Height:25
Text:Selected to PNG
Font:Bold
Button@EXTRACT_BUTTON:
X:PARENT_RIGHT - 200
Y:115
Width:160
Height:25
Text:Extract all to PNG
Font:Bold
TextField@IMAGE_FILENAME_INPUT:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 235
Width:100
Height:25
Text:pixelart.png
TextField@IMAGE_SIZE_INPUT:
X:PARENT_RIGHT - 90
Y:PARENT_BOTTOM - 235
Width:50
Height:25
Text:width
Button@IMPORT_BUTTON:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 200
Width:160
Height:25
Text:Import from PNG
Font:Bold
Button@CLOSE_BUTTON:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 115
Width:160
Height:25
Text:Close
Font:Bold
Key:escape
Container@FRAME_SELECTOR:
X:45
Y:360
Children:
Button@BUTTON_PREV:
X:0
Y:0
Width:25
Height:25
Children:
Image@IMAGE_PREV:
X:0
Y:0
Width:25
Height:25
ImageCollection:music
ImageName:prev
Button@BUTTON_PLAY:
X:35
Y:0
Width:25
Height:25
Children:
Image@IMAGE_PLAY:
X:0
Y:0
Width:25
Height:25
ImageCollection:music
ImageName:play
Button@BUTTON_PAUSE:
Visible: no
X:35
Y:0
Width:25
Height:25
Children:
Image@IMAGE_PAUSE:
X:0
Y:0
Width:25
Height:25
ImageCollection:music
ImageName:pause
Button@BUTTON_STOP:
X:70
Y:0
Width:25
Height:25
Children:
Image@IMAGE_STOP:
X:0
Y:0
Width:25
Height:25
ImageCollection:music
ImageName:stop
Button@BUTTON_NEXT:
X:105
Y:0
Width:25
Height:25
Children:
Image@IMAGE_NEXT:
X:0
Y:0
Width:25
Height:25
ImageCollection:music
ImageName:next
Slider@FRAME_SLIDER:
X:160
Y:0
Width:410
Height:20
MinimumValue: 0
Label@FRAME_COUNT:
X:585
Y:0
Width:25
Height:25
Font:Bold

View File

@@ -30,8 +30,10 @@ Background@COLOR_CHOOSER:
Width:144 Width:144
Height:72 Height:72
ShpImage@FACT: ShpImage@FACT:
X:160 X:153
Y:8 Y:1
Width:80
Height:73
Image:DATA.R8 Image:DATA.R8
Frame:1936 Frame:1936
Palette:colorpicker Palette:colorpicker

View File

@@ -150,6 +150,8 @@ Container@PLAYER_WIDGETS:
SupportPowerBin@INGAME_POWERS_BIN: SupportPowerBin@INGAME_POWERS_BIN:
X:0 X:0
Y:25 Y:25
IconWidth: 60
IconHeight: 48
ReadyText: READY ReadyText: READY
HoldText: ON HOLD HoldText: ON HOLD
BuildPalette@INGAME_BUILD_PALETTE: BuildPalette@INGAME_BUILD_PALETTE:

View File

@@ -2,10 +2,10 @@ ShadowIndex: 1
Palettes: Palettes:
cursor: cursor.pal cursor: cursor.pal
mouse.r8: d2k.pal mouse: d2k.pal
Cursors: Cursors:
mouse.r8: mouse.r8 mouse.r8: mouse
scroll-t: scroll-t:
start:112 start:112
x: 24 x: 24
@@ -252,7 +252,7 @@ Cursors:
x: 24 x: 24
y: 24 y: 24
nopower: cursor nopower.shp: cursor
powerdown-blocked: powerdown-blocked:
start:0 start:0
length: 1 length: 1

View File

@@ -76,8 +76,7 @@ ChromeLayout:
mods/ra/chrome/cheats.yaml mods/ra/chrome/cheats.yaml
mods/ra/chrome/musicplayer.yaml mods/ra/chrome/musicplayer.yaml
mods/d2k/chrome/tooltips.yaml mods/d2k/chrome/tooltips.yaml
mods/d2k/chrome/assetbrowser.yaml mods/ra/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml mods/ra/chrome/irc.yaml
Weapons: Weapons:

View File

@@ -1,27 +1,27 @@
carryall: carryall:
idle: DATA.R8 idle: DATA
Start: 1923 Start: 1923
Facings: -32 Facings: -32
unload: DATA.R8 unload: DATA
Start: 1923 Start: 1923
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4029 Start: 4029
Offset: -30,-24 Offset: -30,-24
orni: orni:
idle: DATA.R8 idle: DATA
Start: 1955 Start: 1955
Facings: -32 Facings: -32
Length: 3 Length: 3
Tick: 120 Tick: 120
Transpose: true Transpose: true
icon: DATA.R8 icon: DATA
Start: 4031 Start: 4031
Offset: -30,-24 Offset: -30,-24
frigate: frigate:
idle: DATA.R8 idle: DATA
Start: 2517 Start: 2517
Facings: 1 Facings: 1

View File

@@ -1,441 +1,441 @@
rifle: rifle:
stand: DATA.R8 stand: DATA
Start: 206 Start: 206
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 206 Start: 206
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand3: DATA.R8 stand3: DATA
Start: 206 Start: 206
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 214 Start: 214
Length: 6 Length: 6
Facings: -8 Facings: -8
Tick: 110 Tick: 110
Transpose: true Transpose: true
shoot: DATA.R8 shoot: DATA
Start: 254 Start: 254
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-stand: DATA.R8 prone-stand: DATA
Start: 302 Start: 302
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-run: DATA.R8 prone-run: DATA
Start: 310 Start: 310
Length: 3 Length: 3
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 110 Tick: 110
standup-0: DATA.R8 standup-0: DATA
Start: 302 Start: 302
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
prone-shoot: DATA.R8 prone-shoot: DATA
Start: 334 Start: 334
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
die1: DATA.R8 die1: DATA
Start: 382 Start: 382
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 387 Start: 387
Length: 7 Length: 7
Tick: 80 Tick: 80
die3: DATA.R8 die3: DATA
Start: 394 Start: 394
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 401 Start: 401
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 408 Start: 408
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 415 Start: 415
Length: 12 Length: 12
die-crushed: DATA.R8 die-crushed: DATA
Start: 430 Start: 430
Length: 12 Length: 12
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4011 Start: 4011
Offset: -30,-24 Offset: -30,-24
bazooka: bazooka:
stand: DATA.R8 stand: DATA
Start: 458 Start: 458
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 458 Start: 458
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand3: DATA.R8 stand3: DATA
Start: 458 Start: 458
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 466 Start: 466
Length: 6 Length: 6
Facings: -8 Facings: -8
Tick: 120 Tick: 120
Transpose: true Transpose: true
shoot: DATA.R8 shoot: DATA
Start: 506 Start: 506
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-stand: DATA.R8 prone-stand: DATA
Start: 562 Start: 562
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-run: DATA.R8 prone-run: DATA
Start: 570 Start: 570
Length: 3 Length: 3
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
standup-0: DATA.R8 standup-0: DATA
Start: 554 Start: 554
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-shoot: DATA.R8 prone-shoot: DATA
Start: 586 Start: 586
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
die1: DATA.R8 die1: DATA
Start: 634 Start: 634
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 639 Start: 639
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 646 Start: 646
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 653 Start: 653
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 660 Start: 660
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 660 Start: 660
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 668 Start: 668
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4012 Start: 4012
Offset: -30,-24 Offset: -30,-24
engineer: engineer:
stand: DATA.R8 stand: DATA
Start: 1166 Start: 1166
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 1166 Start: 1166
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 1174 Start: 1174
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
die1: DATA.R8 die1: DATA
Start: 1342 Start: 1342
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 1347 Start: 1347
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 1354 Start: 1354
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 1361 Start: 1361
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 1368 Start: 1368
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 1368 Start: 1368
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 1376 Start: 1376
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4013 Start: 4013
Offset: -30,-24 Offset: -30,-24
medic: # actually thumper medic: # actually thumper
stand: DATA.R8 stand: DATA
Start: 1402 Start: 1402
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 1402 Start: 1402
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 1410 Start: 1410
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
heal: DATA.R8 heal: DATA
Start: 1458 Start: 1458
Length: 5 Length: 5
Tick: 480 Tick: 480
die1: DATA.R8 die1: DATA
Start: 1543 Start: 1543
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 1548 Start: 1548
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 1555 Start: 1555
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 1562 Start: 1562
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 1569 Start: 1569
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 1569 Start: 1569
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 1577 Start: 1577
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4014 Start: 4014
Offset: -30,-24 Offset: -30,-24
thumping: thumping:
idle: DATA.R8 idle: DATA
Start: 1458 Start: 1458
Length: 5 Length: 5
Tick: 150 Tick: 150
make: DATA.R8 make: DATA
Start: 1458 Start: 1458
Length: 5 Length: 5
damaged-idle: DATA.R8 damaged-idle: DATA
Start: 1458 Start: 1458
Length: 5 Length: 5
Tick: 150 Tick: 150
icon: DATA.R8 icon: DATA
Frames: 4014 Frames: 4014
Offset: -30,-24 Offset: -30,-24
fremen: fremen:
stand: DATA.R8 stand: DATA
Start: 694 Start: 694
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 694 Start: 694
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 702 Start: 702
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
shoot: DATA.R8 shoot: DATA
Start: 742 Start: 742
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-stand: DATA.R8 prone-stand: DATA
Start: 798 Start: 798
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-run: DATA.R8 prone-run: DATA
Start: 806 Start: 806
Length: 3 Length: 3
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
standup-0: DATA.R8 standup-0: DATA
Start: 790 Start: 790
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
prone-shoot: DATA.R8 prone-shoot: DATA
Start: 822 Start: 822
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
die1: DATA.R8 die1: DATA
Start: 870 Start: 870
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 875 Start: 875
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 882 Start: 882
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 889 Start: 889
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 896 Start: 896
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 896 Start: 896
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 904 Start: 904
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4032 Start: 4032
Offset: -30,-24 Offset: -30,-24
saboteur: saboteur:
stand: DATA.R8 stand: DATA
Start: 2149 Start: 2149
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 2149 Start: 2149
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand3: DATA.R8 stand3: DATA
Start: 2149 Start: 2149
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 2157 Start: 2157
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
prone-stand: DATA.R8 prone-stand: DATA
Start: 2253 Start: 2253
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-run: DATA.R8 prone-run: DATA
Start: 2261 Start: 2261
Length: 3 Length: 3
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
standup-0: DATA.R8 standup-0: DATA
Start: 2245 Start: 2245
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
die1: DATA.R8 die1: DATA
Start: 2325 Start: 2325
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 2330 Start: 2330
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 2337 Start: 2337
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 2344 Start: 2344
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 2351 Start: 2351
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 2351 Start: 2351
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 2359 Start: 2359
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4034 Start: 4034
Offset: -30,-24 Offset: -30,-24
sardaukar: sardaukar:
stand: DATA.R8 stand: DATA
Start: 930 Start: 930
Facings: -8 Facings: -8
Transpose: true Transpose: true
stand2: DATA.R8 stand2: DATA
Start: 930 Start: 930
Facings: -8 Facings: -8
Transpose: true Transpose: true
run: DATA.R8 run: DATA
Start: 938 Start: 938
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
shoot: DATA.R8 shoot: DATA
Start: 978 Start: 978
Length: 6 Length: 6
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-stand: DATA.R8 prone-stand: DATA
Start: 1034 Start: 1034
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
prone-run: DATA.R8 prone-run: DATA
Start: 1042 Start: 1042
Length: 3 Length: 3
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
standup-0: DATA.R8 standup-0: DATA
Start: 1026 Start: 1026
Length: 1 Length: 1
Facings: -8 Facings: -8
Transpose: true Transpose: true
Tick: 120 Tick: 120
prone-shoot: DATA.R8 prone-shoot: DATA
Start: 1058 Start: 1058
Length: 6 Length: 6
Facings: 8 Facings: 8
Transpose: true Transpose: true
die1: DATA.R8 die1: DATA
Start: 1106 Start: 1106
Length: 5 Length: 5
die2: DATA.R8 die2: DATA
Start: 1111 Start: 1111
Length: 7 Length: 7
die3: DATA.R8 die3: DATA
Start: 1118 Start: 1118
Length: 7 Length: 7
die4: DATA.R8 die4: DATA
Start: 1125 Start: 1125
Length: 7 Length: 7
die5: DATA.R8 die5: DATA
Start: 1132 Start: 1132
Length: 7 Length: 7
die6: DATA.R8 die6: DATA
Start: 1132 Start: 1132
Length: 7 Length: 7
die-crushed: DATA.R8 die-crushed: DATA
Start: 1140 Start: 1140
Length: 26 Length: 26
Tick: 1600 Tick: 1600
icon: DATA.R8 icon: DATA
Start: 4015 Start: 4015
Offset: -30,-24 Offset: -30,-24

View File

@@ -1,87 +1,87 @@
explosion: explosion:
piff: DATA.R8 piff: DATA
Start: 3626 Start: 3626
Length: 5 Length: 5
piffs: DATA.R8 piffs: DATA
Start: 3429 Start: 3429
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: Additive BlendMode: Additive
small_explosion: DATA.R8 small_explosion: DATA
Start: 3403 Start: 3403
Length: 15 Length: 15
BlendMode: Additive BlendMode: Additive
med_explosion: DATA.R8 med_explosion: DATA
Start: 3390 Start: 3390
Length: 12 Length: 12
BlendMode: Additive BlendMode: Additive
tiny_explosion: DATA.R8 tiny_explosion: DATA
Start: 3386 Start: 3386
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: Additive BlendMode: Additive
nuke: DATA.R8 nuke: DATA
Start: 3965 Start: 3965
Length: 14 Length: 14
Tick: 60 Tick: 60
BlendMode: Additive BlendMode: Additive
mini_explosion: DATA.R8 mini_explosion: DATA
Start: 3403 Start: 3403
Length: 15 Length: 15
Tick: 60 Tick: 60
BlendMode: Additive BlendMode: Additive
self_destruct: DATA.R8 self_destruct: DATA
Start: 3433 Start: 3433
Length: 15 Length: 15
BlendMode: Additive BlendMode: Additive
building: DATA.R8 building: DATA
Start: 3448 Start: 3448
Length: 22 Length: 22
BlendMode: Additive BlendMode: Additive
large_explosion: DATA.R8 large_explosion: DATA
Start: 3988 Start: 3988
Length: 22 Length: 22
BlendMode: Additive BlendMode: Additive
artillery: DATA.R8 artillery: DATA
Start: 3988 Start: 3988
Length: 22 Length: 22
BlendMode: Additive BlendMode: Additive
small_artillery: DATA.R8 small_artillery: DATA
Start: 3390 Start: 3390
Length: 12 Length: 12
Tick: 60 Tick: 60
BlendMode: Additive BlendMode: Additive
small_napalm: DATA.R8 small_napalm: DATA
Start: 3421 Start: 3421
Length: 8 Length: 8
BlendMode: Additive BlendMode: Additive
shockwave: DATA.R8 shockwave: DATA
Start: 3687 Start: 3687
Length: 6 Length: 6
BlendMode: Additive BlendMode: Additive
Tick: 120 Tick: 120
deviator: DATA.R8 deviator: DATA
Start: 3512 Start: 3512
Length: 23 Length: 23
BlendMode: Additive BlendMode: Additive
Tick: 60 Tick: 60
laserfire: laserfire:
idle: DATA.R8 idle: DATA
Start: 3386 Start: 3386
Length: 4 Length: 4
Tick: 80 Tick: 80
BlendMode: Additive BlendMode: Additive
pips: pips:
groups: DATA.R8 groups: DATA
Start: 17 Start: 17
Length: 10 Length: 10
tag-primary: DATA.R8 tag-primary: DATA
Start: 110 Start: 110
pip-empty: DATA.R8 pip-empty: DATA
Start: 15 Start: 15
pip-green: DATA.R8 pip-green: DATA
Start: 16 Start: 16
clock: clock:
@@ -105,19 +105,19 @@ rank:
Length: * Length: *
overlay: overlay:
build-valid-arrakis: DATA.R8 build-valid-arrakis: DATA
Start: 0 Start: 0
Offset: -16,-16 Offset: -16,-16
build-invalid: DATA.R8 build-invalid: DATA
Start: 1 Start: 1
Offset: -16,-16 Offset: -16,-16
target-select: DATA.R8 target-select: DATA
Start: 2 Start: 2
Offset: -16,-16 Offset: -16,-16
target-valid-arrakis: DATA.R8 target-valid-arrakis: DATA
Start: 0 Start: 0
Offset: -16,-16 Offset: -16,-16
target-invalid: DATA.R8 target-invalid: DATA
Start: 1 Start: 1
Offset: -16,-16 Offset: -16,-16
@@ -131,29 +131,29 @@ rallypoint:
Length: * Length: *
rpg: rpg:
idle: DATA.R8 idle: DATA
Start: 3015 Start: 3015
Facings: -32 Facings: -32
120mm: 120mm:
idle: DATA.R8 idle: DATA
Start: 3014 Start: 3014
Length: 1 Length: 1
BlendMode: Additive BlendMode: Additive
155mm: 155mm:
idle: DATA.R8 idle: DATA
Start: 3081 Start: 3081
Length: 1 Length: 1
crate-effects: crate-effects:
dollar: DATA.R8 dollar: DATA
Start: 3679 Start: 3679
Length: 8 Length: 8
reveal-map: DATA.R8 reveal-map: DATA
Start: 3947 Start: 3947
Length: 18 Length: 18
hide-map: DATA.R8 hide-map: DATA
Start: 3911 Start: 3911
Length: 36 Length: 36
levelup: levelup levelup: levelup
@@ -162,70 +162,70 @@ crate-effects:
Tick: 200 Tick: 200
allyrepair: allyrepair:
repair: DATA.R8 repair: DATA
Frames: 3, 39 Frames: 3, 39
Length: 2 Length: 2
Tick: 300 Tick: 300
missile: missile:
idle: DATA.R8 idle: DATA
Start: 3088 Start: 3088
Facings: -32 Facings: -32
missile2: missile2:
idle: DATA.R8 idle: DATA
Start: 3306 Start: 3306
Facings: -32 Facings: -32
atomic: atomic:
up: DATA.R8 up: DATA
Start: 2147 Start: 2147
Length: 1 Length: 1
down: DATA.R8 down: DATA
Start: 2148 Start: 2148
Length: 1 Length: 1
fire: fire:
1: DATA.R8 1: DATA
Start: 3712 Start: 3712
Length: 10 Length: 10
Offset: 0,-3 Offset: 0,-3
BlendMode: Additive BlendMode: Additive
2: DATA.R8 2: DATA
Start: 3723 Start: 3723
Length: 11 Length: 11
Offset: 0,-3 Offset: 0,-3
BlendMode: Additive BlendMode: Additive
3: DATA.R8 3: DATA
Start: 3885 Start: 3885
Length: 13 Length: 13
Offset: 0,-3 Offset: 0,-3
BlendMode: Additive BlendMode: Additive
4: DATA.R8 4: DATA
Start: 3712 Start: 3712
Length: 10 Length: 10
Offset: 0,-3 Offset: 0,-3
BlendMode: Additive BlendMode: Additive
smoke_m: smoke_m:
idle: DATA.R8 idle: DATA
Start: 3418 Start: 3418
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
loop: DATA.R8 loop: DATA
Start: 3418 Start: 3418
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
end: DATA.R8 end: DATA
Start: 3418 Start: 3418
Length: 3 Length: 3
BlendMode: Additive BlendMode: Additive
bombs: bombs:
open: DATA.R8 open: DATA
Start: 3280 Start: 3280
Length: 4 Length: 4
idle: DATA.R8 idle: DATA
Start: 3280 Start: 3280
Length: 4 Length: 4
@@ -248,59 +248,59 @@ waypoint:
Length: * Length: *
sietch: sietch:
idle: DATA.R8 idle: DATA
Start: 2998 Start: 2998
doubleblast: doubleblast:
idle: DATA.R8 idle: DATA
Start: 3279 Start: 3279
Facings: -16 Facings: -16
BlendMode: Additive BlendMode: Additive
doubleblastbullet: doubleblastbullet:
idle: DATA.R8 idle: DATA
Start: 3248 Start: 3248
Facings: -16 Facings: -16
BlendMode: Additive BlendMode: Additive
icon: icon:
paratroopers: DATA.R8 paratroopers: DATA
Start: 4029 Start: 4029
Offset: -30,-24 Offset: -30,-24
ornistrike: DATA.R8 ornistrike: DATA
Start: 4031 Start: 4031
Offset: -30,-24 Offset: -30,-24
deathhand: DATA.R8 deathhand: DATA
Start: 4035 Start: 4035
Offset: -30,-24 Offset: -30,-24
crate: crate:
idle: DATA.R8 idle: DATA
Start: 102 Start: 102
ZOffset: -511 ZOffset: -511
Offset: -16,-16 Offset: -16,-16
land: DATA.R8 land: DATA
Start: 102 Start: 102
ZOffset: -511 ZOffset: -511
Offset: -16,-16 Offset: -16,-16
spicebloom: spicebloom:
make: DATA.R8 make: DATA
Start: 107 Start: 107
Length: 3 Length: 3
Offset: -16,-16 Offset: -16,-16
active: DATA.R8 active: DATA
Start: 109 Start: 109
Length: 1 Length: 1
ZOffset: -511 ZOffset: -511
Offset: -16,-16 Offset: -16,-16
idle: DATA.R8 idle: DATA
Start: 109 Start: 109
ZOffset: -511 ZOffset: -511
Offset: -16,-16 Offset: -16,-16
moveflsh: moveflsh:
idle: DATA.R8 idle: DATA
Start: 3621 Start: 3621
Length: 5 Length: 5
Tick: 80 Tick: 80

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +1,174 @@
dmcv: dmcv:
idle: DATA.R8 idle: DATA
Start: 1795 Start: 1795
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4023 Start: 4023
Offset: -30,-24 Offset: -30,-24
harvester: harvester:
idle: DATA.R8 idle: DATA
Start: 1699 Start: 1699
Facings: -32 Facings: -32
harvest: DATA.R8 harvest: DATA
Start: 3631 Start: 3631
Length: 6 Length: 6
Facings: -8 Facings: -8
Tick: 80 Tick: 80
ZOffset: 1 ZOffset: 1
dock: DATA.R8 dock: DATA
Start: 3370 Start: 3370
Length: 10 Length: 10
dock-loop: DATA.R8 dock-loop: DATA
Start: 3380 Start: 3380
Length: 1 Length: 1
icon: DATA.R8 icon: DATA
Start: 4019 Start: 4019
Offset: -30,-24 Offset: -30,-24
trike: trike:
idle: DATA.R8 idle: DATA
Start: 1635 Start: 1635
Facings: -32 Facings: -32
unload: DATA.R8 unload: DATA
Start: 1635 Start: 1635
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842, 3843, 3843, 3844, 3844, 3845, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851, 3851, 3852, 3852, 3853, 3853, 3854, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859, 3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3865, 3866, 3866, 3867, 3867, 3868, 3868, 3869, 3869, 3870, 3870 Frames: 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842, 3843, 3843, 3844, 3844, 3845, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851, 3851, 3852, 3852, 3853, 3853, 3854, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859, 3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3865, 3866, 3866, 3867, 3867, 3868, 3868, 3869, 3869, 3870, 3870
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4041 Start: 4041
Offset: -30,-24 Offset: -30,-24
quad: quad:
idle: DATA.R8 idle: DATA
Start: 1667 Start: 1667
Facings: -32 Facings: -32
unload: DATA.R8 unload: DATA
Start: 1667 Start: 1667
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4018 Start: 4018
Offset: -30,-24 Offset: -30,-24
siegetank: siegetank:
idle: DATA.R8 idle: DATA
Start: 1763 Start: 1763
Facings: -32 Facings: -32
turret: DATA.R8 turret: DATA
Start: 1891 Start: 1891
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Start: 3418 Start: 3418
Length: 3 Length: 3
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4026 Start: 4026
Offset: -30,-24 Offset: -30,-24
missiletank: missiletank:
idle: DATA.R8 idle: DATA
Start: 1603 Start: 1603
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4024 Start: 4024
Offset: -30,-24 Offset: -30,-24
sonictank: sonictank:
idle: DATA.R8 idle: DATA
Start: 1827 Start: 1827
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4027 Start: 4027
Offset: -30,-24 Offset: -30,-24
combata: combata:
idle: DATA.R8 idle: DATA
Start: 1731 Start: 1731
Facings: -32 Facings: -32
turret: DATA.R8 turret: DATA
Start: 1859 Start: 1859
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4020 Start: 4020
Offset: -30,-24 Offset: -30,-24
combath: combath:
idle: DATA.R8 idle: DATA
Start: 2051 Start: 2051
Facings: -32 Facings: -32
turret: DATA.R8 turret: DATA
Start: 2115 Start: 2115
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4021 Start: 4021
Offset: -30,-24 Offset: -30,-24
devast: devast:
idle: DATA.R8 idle: DATA
Start: 2083 Start: 2083
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3807, 3807, 3808, 3808, 3809, 3809, 3810, 3810, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3816, 3816, 3817, 3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825, 3826, 3826, 3827, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3832, 3833, 3833, 3834, 3834, 3835, 3835, 3836, 3836, 3837, 3837, 3838, 3838 Frames: 3807, 3807, 3808, 3808, 3809, 3809, 3810, 3810, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3816, 3816, 3817, 3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825, 3826, 3826, 3827, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3832, 3833, 3833, 3834, 3834, 3835, 3835, 3836, 3836, 3837, 3837, 3838, 3838
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4028 Start: 4028
Offset: -30,-24 Offset: -30,-24
combato: combato:
idle: DATA.R8 idle: DATA
Start: 2453 Start: 2453
Facings: -32 Facings: -32
turret: DATA.R8 turret: DATA
Start: 2485 Start: 2485
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4022 Start: 4022
Offset: -30,-24 Offset: -30,-24
raider: raider:
idle: DATA.R8 idle: DATA
Start: 2421 Start: 2421
Facings: -32 Facings: -32
unload: DATA.R8 unload: DATA
Start: 2421 Start: 2421
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774 Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774
Facings: -32 Facings: -32
Length: 2 Length: 2
BlendMode: Additive BlendMode: Additive
icon: DATA.R8 icon: DATA
Start: 4017 Start: 4017
Offset: -30,-24 Offset: -30,-24
stealthraider: stealthraider:
idle: DATA.R8 idle: DATA
Start: 2421 Start: 2421
Facings: -32 Facings: -32
unload: DATA.R8 unload: DATA
Start: 2421 Start: 2421
Facings: -32 Facings: -32
muzzle: DATA.R8 muzzle: DATA
Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774 Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774
Facings: -32 Facings: -32
Length: 2 Length: 2
@@ -177,9 +177,9 @@ stealthraider:
Start: 0 Start: 0
deviatortank: deviatortank:
idle: DATA.R8 idle: DATA
Start: 2389 Start: 2389
Facings: -32 Facings: -32
icon: DATA.R8 icon: DATA
Start: 4025 Start: 4025
Offset: -30,-24 Offset: -30,-24

View File

@@ -3,7 +3,7 @@ General:
Id: ARRAKIS Id: ARRAKIS
SheetSize: 1024 SheetSize: 1024
Palette: d2k.pal Palette: d2k.pal
Extensions: .R8, .shp Extensions: .R8, .r8, .shp
Terrain: Terrain:
TerrainType@Sand: TerrainType@Sand:

View File

@@ -3,29 +3,36 @@ Background@ASSETBROWSER_BG:
X:(WINDOW_RIGHT - WIDTH)/2 X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:700 Width:700
Height:410 Height:500
Children: Children:
ColorPreviewManager@COLOR_MANAGER: ColorPreviewManager@COLOR_MANAGER:
Label@ASSETBROWSER_TITLE: Label@ASSETBROWSER_TITLE:
X:0 Y:20
Y:10
Width:PARENT_RIGHT Width:PARENT_RIGHT
Height:25 Height:25
Text:Game Asset Viewer & Converter
Align:Center
Font:Bold Font:Bold
Align:Center
Text:Asset Browser
Label@SOURCE_SELECTOR_DESC:
X:20
Y:35
Width:160
Height:25
Font:TinyBold
Align:Center
Text:Select asset source
DropDownButton@SOURCE_SELECTOR: DropDownButton@SOURCE_SELECTOR:
X:40 X:20
Y:45 Y:60
Width:160 Width:160
Height:25 Height:25
Font:Bold Font:Bold
Text:Folders Text:Folders
ScrollPanel@ASSET_LIST: ScrollPanel@ASSET_LIST:
X:40 X:20
Y:80 Y:90
Width:160 Width:160
Height:190 Height:275
Children: Children:
ScrollItem@ASSET_TEMPLATE: ScrollItem@ASSET_TEMPLATE:
Width:PARENT_RIGHT-27 Width:PARENT_RIGHT-27
@@ -38,30 +45,45 @@ Background@ASSETBROWSER_BG:
X:10 X:10
Width:PARENT_RIGHT-20 Width:PARENT_RIGHT-20
Height:25 Height:25
Label@FILENAME_DESC:
X:20
Y:370
Width:160
Height:25
Font:TinyBold
Align:Center
Text:Search for file
TextField@FILENAME_INPUT: TextField@FILENAME_INPUT:
X:40 X:20
Y:280 Y:395
Width:140 Width:160
Height:25 Height:25
Text:mouse.shp Text:mouse.shp
Button@LOAD_BUTTON: Button@LOAD_BUTTON:
X:40 X:20
Y:310 Y:425
Width:140 Width:160
Height:25 Height:25
Text:Load Text:Load
Font:Bold Font:Bold
Key:return Key:return
DropDownButton@PALETTE_SELECTOR: Label@PALETTE_DESC:
X:230 X:PARENT_RIGHT-WIDTH-270
Y:45 Y:60
Width:150
Height:25
Font:Bold
Align:Right
Text:Palette:
DropDownButton@PALETTE_SELECTOR:
X:PARENT_RIGHT-WIDTH-110
Y:60
Width:150 Width:150
Height:25 Height:25
Font:Bold Font:Bold
Text:Palette
DropDownButton@COLOR: DropDownButton@COLOR:
X:380 X:PARENT_RIGHT-WIDTH-20
Y:45 Y:60
Width:80 Width:80
Height:25 Height:25
Children: Children:
@@ -71,69 +93,19 @@ Background@ASSETBROWSER_BG:
Width:PARENT_RIGHT-35 Width:PARENT_RIGHT-35
Height:PARENT_BOTTOM-12 Height:PARENT_BOTTOM-12
Background@SPRITE_BG: Background@SPRITE_BG:
X:220 X:190
Y:80 Y:90
Width:250 Width:490
Height:250 Height:330
Background:dialog4 Background:dialog3
Children: Children:
ShpImage@SPRITE: ShpImage@SPRITE:
X:4 Width:PARENT_RIGHT
Y:4 Height:PARENT_BOTTOM
Width:246
Height:246
Image:mouse Image:mouse
Label@ACTIONS_TITLE:
X:PARENT_RIGHT - 150
Y:45
Width:PARENT_RIGHT
Height:25
Text:Actions
Font:Bold
Button@EXPORT_BUTTON:
X:PARENT_RIGHT - 200
Y:80
Width:160
Height:25
Text:Selected to PNG
Font:Bold
Button@EXTRACT_BUTTON:
X:PARENT_RIGHT - 200
Y:115
Width:160
Height:25
Text:Extract all to PNG
Font:Bold
TextField@IMAGE_FILENAME_INPUT:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 235
Width:100
Height:25
Text:pixelart.png
TextField@IMAGE_SIZE_INPUT:
X:PARENT_RIGHT - 90
Y:PARENT_BOTTOM - 235
Width:50
Height:25
Text:width
Button@IMPORT_BUTTON:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 200
Width:160
Height:25
Text:Import from PNG
Font:Bold
Button@CLOSE_BUTTON:
X:PARENT_RIGHT - 200
Y:PARENT_BOTTOM - 115
Width:160
Height:25
Text:Close
Font:Bold
Key:escape
Container@FRAME_SELECTOR: Container@FRAME_SELECTOR:
X:45 X:190
Y:360 Y:425
Children: Children:
Button@BUTTON_PREV: Button@BUTTON_PREV:
X:0 X:0
@@ -202,14 +174,22 @@ Background@ASSETBROWSER_BG:
ImageCollection:music ImageCollection:music
ImageName:next ImageName:next
Slider@FRAME_SLIDER: Slider@FRAME_SLIDER:
X:160 X:140
Y:0 Y:3
Width:410 Width:300
Height:20 Height:20
MinimumValue: 0 MinimumValue: 0
Label@FRAME_COUNT: Label@FRAME_COUNT:
X:585 X:445
Y:0 Width:40
Width:25
Height:25 Height:25
Font:Bold Font:TinyBold
Align:Left
Button@CLOSE_BUTTON:
Key:escape
X:PARENT_RIGHT-180
Y:PARENT_BOTTOM-45
Width:160
Height:25
Font:Bold
Text:Close

View File

@@ -30,8 +30,10 @@ Background@COLOR_CHOOSER:
Width:144 Width:144
Height:72 Height:72
ShpImage@FACT: ShpImage@FACT:
X:156 X:153
Y:1 Y:1
Width:80
Height:73
Image:fact Image:fact
Palette:colorpicker Palette:colorpicker
Button@RANDOM_BUTTON: Button@RANDOM_BUTTON:

View File

@@ -1,47 +0,0 @@
Background@CONVERT_ASSETS_PANEL:
Logic:ConvertGameFilesLogic
X:(WINDOW_RIGHT - WIDTH)/2
Y:(WINDOW_BOTTOM - HEIGHT)/2
Width:500
Height:160
Children:
Label@TITLE:
X:0
Y:20
Width:PARENT_RIGHT
Height:25
Text:Extracting and Converting Gamefiles
Align:Center
Font:Bold
Container@EXTRACTING:
Width:PARENT_RIGHT
Height:PARENT_BOTTOM
Visible: false
Children:
ProgressBar@PROGRESS_BAR:
X:50
Y:55
Width:PARENT_RIGHT - 100
Height:25
Label@STATUS_LABEL:
X:50
Y:80
Width:PARENT_RIGHT - 100
Height:25
Align:Left
Button@RETRY_BUTTON:
X:PARENT_RIGHT - 280
Y:PARENT_BOTTOM - 45
Width:120
Height:25
Text:Retry
Font:Bold
Key:return
Button@BACK_BUTTON:
X:PARENT_RIGHT - 140
Y:PARENT_BOTTOM - 45
Width:120
Height:25
Text:Back
Font:Bold
Key:escape

View File

@@ -7,14 +7,15 @@ Background@MODS_PANEL:
Children: Children:
Label@TITLE: Label@TITLE:
Text:Select Mod Text:Select Mod
Width:PARENT_RIGHT
Y:20 Y:20
Width:PARENT_RIGHT
Height:25
Font:Bold Font:Bold
Align:Center Align:Center
ScrollPanel@MOD_LIST: ScrollPanel@MOD_LIST:
X:15 X:20
Y:70 Y:70
Width:710 Width:700
Height:PARENT_BOTTOM - 125 Height:PARENT_BOTTOM - 125
Children: Children:
ScrollItem@MOD_TEMPLATE: ScrollItem@MOD_TEMPLATE:

View File

@@ -2,7 +2,7 @@
cursor: cursor.pal cursor: cursor.pal
Cursors: Cursors:
mouse: cursor mouse.shp: cursor
scroll-t: scroll-t:
start:1 start:1
scroll-tr: scroll-tr:
@@ -163,7 +163,7 @@ Cursors:
start:148 start:148
length: 12 length: 12
nopower: cursor nopower.shp: cursor
powerdown-blocked: powerdown-blocked:
start:0 start:0
length: 1 length: 1

View File

@@ -92,7 +92,6 @@ ChromeLayout:
mods/ra/chrome/musicplayer.yaml mods/ra/chrome/musicplayer.yaml
mods/ra/chrome/tooltips.yaml mods/ra/chrome/tooltips.yaml
mods/ra/chrome/assetbrowser.yaml mods/ra/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml mods/ra/chrome/irc.yaml
Weapons: Weapons:

View File

@@ -30,8 +30,10 @@ Background@COLOR_CHOOSER:
Width:144 Width:144
Height:72 Height:72
ShpImage@GTCNST: ShpImage@GTCNST:
X:121 X:153
Y:0-68 Y:1-40
Width:80
Height:73
Image:gtcnstmk Image:gtcnstmk
Palette:colorpicker Palette:colorpicker
Button@RANDOM_BUTTON: Button@RANDOM_BUTTON:

View File

@@ -2,7 +2,7 @@
cursor: mousepal.pal cursor: mousepal.pal
Cursors: Cursors:
mouse: cursor mouse.shp: cursor
scroll-t: #TODO scroll-t: #TODO
start: 2 start: 2
scroll-tr: #TODO scroll-tr: #TODO

View File

@@ -120,7 +120,6 @@ ChromeLayout:
mods/ra/chrome/musicplayer.yaml mods/ra/chrome/musicplayer.yaml
mods/ra/chrome/tooltips.yaml mods/ra/chrome/tooltips.yaml
mods/ra/chrome/assetbrowser.yaml mods/ra/chrome/assetbrowser.yaml
mods/ra/chrome/convertassets.yaml
mods/ra/chrome/irc.yaml mods/ra/chrome/irc.yaml
Weapons: Weapons: