diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/Picture/ChaosWorksSprite.uexml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/Picture/ChaosWorksSprite.uexml
deleted file mode 100644
index 2dd771a3..00000000
--- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Associations/Picture/ChaosWorksSprite.uexml
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
- *.sph
-
-
-
- CWE sprite
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Extensions/ChaosWorks/Associations/Multimedia/PictureCollection/SPXDataFormat.uexml b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Extensions/ChaosWorks/Associations/Multimedia/PictureCollection/SPXDataFormat.uexml
new file mode 100644
index 00000000..c1d70f10
--- /dev/null
+++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/Extensions/GameDeveloper/Extensions/ChaosWorks/Associations/Multimedia/PictureCollection/SPXDataFormat.uexml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+ *.spl
+
+
+
+
+ *.sph
+
+
+
+
+ *.spx
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
index eeb02895..7eb05d90 100644
--- a/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
+++ b/CSharp/Content/UniversalEditor.Content.PlatformIndependent/UniversalEditor.Content.PlatformIndependent.csproj
@@ -207,7 +207,6 @@
-
@@ -670,6 +669,7 @@
+
@@ -711,6 +711,7 @@
+
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs b/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs
new file mode 100644
index 00000000..bdb794d3
--- /dev/null
+++ b/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/DataFormats/Multimedia/PictureCollection/CWESpriteDataFormat.cs
@@ -0,0 +1,173 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MBS.Framework.Drawing;
+using UniversalEditor.Accessors;
+using UniversalEditor.ObjectModels.Multimedia.Palette;
+using UniversalEditor.ObjectModels.Multimedia.Picture;
+using UniversalEditor.ObjectModels.Multimedia.Picture.Collection;
+
+namespace UniversalEditor.Plugins.ChaosWorks.DataFormats.Multimedia.PictureCollection
+{
+ public class CWESpriteDataFormat : DataFormat
+ {
+ private static DataFormatReference _dfr = null;
+ protected override DataFormatReference MakeReferenceInternal()
+ {
+ if (_dfr == null)
+ {
+ _dfr = base.MakeReferenceInternal();
+ _dfr.Capabilities.Add(typeof(PictureCollectionObjectModel), DataFormatCapabilities.All);
+ _dfr.ImportOptions.Add(new CustomOptionFile("ExternalPaletteFileName", "External _palette file name"));
+ }
+ return _dfr;
+ }
+
+ public string ExternalPaletteFileName { get; set; } = null;
+ public PaletteObjectModel EmbeddedPalette { get; set; } = null;
+
+ protected override void LoadInternal(ref ObjectModel objectModel)
+ {
+ PictureCollectionObjectModel coll = (objectModel as PictureCollectionObjectModel);
+
+ IO.Reader br = base.Accessor.Reader;
+ br.Accessor.Position = 0;
+
+ string CWE_sprite = br.ReadNullTerminatedString();
+ if (CWE_sprite != "CWE sprite") throw new InvalidDataFormatException();
+ uint always36 = br.ReadUInt32(); // always the same?
+ uint always12 = br.ReadUInt32(); // always the same?
+ uint key = br.ReadUInt32();
+ uint unknown1 = br.ReadUInt32();
+ uint unknown2 = br.ReadUInt32();
+ uint unknown3 = br.ReadUInt32();
+ uint unknown4 = br.ReadUInt32();
+ uint unknown5 = br.ReadUInt32();
+ uint length = br.ReadUInt32();
+ uint frameCount = br.ReadUInt32();
+
+ br.Accessor.SavePosition();
+ br.Seek(length + 51, IO.SeekOrigin.Begin);
+
+ // frame definition data?
+ uint m_frameWidth = 0;
+ for (uint i = 0; i < frameCount; i++)
+ {
+ uint a = br.ReadUInt32();
+ uint b = br.ReadUInt32();
+ ushort x = br.ReadUInt16();
+ ushort y = br.ReadUInt16();
+ ushort frameWidth = br.ReadUInt16();
+ ushort frameHeight = br.ReadUInt16();
+
+ PictureObjectModel pic = new PictureObjectModel();
+ pic.Width = frameWidth;
+ pic.Height = frameHeight;
+ coll.Pictures.Add(pic);
+
+ if (m_frameWidth == 0)
+ m_frameWidth = frameWidth;
+
+ Console.WriteLine("cwe-sprite: added picture for sprite frame {0}\t{1}\t({2}, {3})\t{4}x{5}", a, b, x, y, frameWidth, frameHeight);
+ }
+
+ PaletteObjectModel palette = new PaletteObjectModel();
+ if (ExternalPaletteFileName != null)
+ {
+ if (System.IO.File.Exists(ExternalPaletteFileName))
+ Document.Load(palette, new Palette.SPPDataFormat(), new FileAccessor(ExternalPaletteFileName));
+ }
+
+ // now we're at the embedded palette
+ if (!br.EndOfStream)// just in case this file doesn't include one; they all seem to have it though
+ {
+ EmbeddedPalette = new PaletteObjectModel();
+ while (!br.EndOfStream)
+ {
+ byte r = br.ReadByte();
+ byte g = br.ReadByte();
+ byte b = br.ReadByte();
+ byte a = br.ReadByte();
+ a = (byte)(255 - a);
+
+ Color color = Color.FromRGBAByte(r, g, b, a);
+ EmbeddedPalette.Entries.Add(color);
+ palette.Entries.Add(color);
+ }
+ }
+ br.Accessor.LoadPosition();
+
+ // now that we've loaded the frame definitions and embedded color palette,
+ // we can go back and read the pixel data
+ List> lists = new List>();
+ for (uint i = 0; i < frameCount; i++)
+ {
+ int x = 0, y = 0;
+ PictureObjectModel pic = coll.Pictures[(int)i];
+ while (!br.EndOfStream)
+ {
+ ushort blockLength = br.ReadUInt16();
+ if (blockLength == ushort.MaxValue)
+ break;
+
+ if (blockLength == 0)
+ continue;
+
+ long blockEnd = br.Accessor.Position + blockLength;
+ ushort chunkFrameCount = br.ReadUInt16();
+
+ for (ushort j = 0; j < chunkFrameCount; j++)
+ {
+ ushort skip_count = br.ReadUInt16();
+ ushort size_count = br.ReadUInt16();
+
+ y += skip_count;
+
+ if ((short)size_count < 0)
+ {
+ // if it is negative a single byte follows, and is repeated -size_count times
+ size_count = (ushort)(-(short)size_count);
+
+ byte index = br.ReadByte();
+ Color color = palette.Entries[index].Color;
+
+ for (int k = 0; k < size_count; k++)
+ {
+ Console.WriteLine("cwe-sprite: setting pixel ({0}, {1}) to color {2}", x, y, color);
+ pic.SetPixel(color, y, x);
+ y++;
+ }
+ }
+ else
+ {
+ for (int k = 0; k < size_count; k++)
+ {
+ byte index = br.ReadByte();
+ Color color = palette.Entries[index].Color;
+
+ Console.WriteLine("cwe-sprite: setting pixel ({0}, {1}) to color {2}", x, y, color);
+ pic.SetPixel(color, y, x);
+ y++;
+ }
+ }
+ }
+
+ if (br.Accessor.Position != blockEnd)
+ {
+ Console.WriteLine("cwe-sprite ERROR: finished reading a block, but not at block end! skipping to end of block anyway...");
+ }
+
+ br.Seek(blockEnd, IO.SeekOrigin.Begin);
+ x++;
+ y = 0;
+ }
+ }
+ }
+
+ protected override void SaveInternal(ObjectModel objectModel)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/UniversalEditor.Plugins.ChaosWorks.csproj b/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/UniversalEditor.Plugins.ChaosWorks.csproj
index 65aaaf36..ff464bbc 100644
--- a/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/UniversalEditor.Plugins.ChaosWorks.csproj
+++ b/CSharp/Plugins/UniversalEditor.Plugins.ChaosWorks/UniversalEditor.Plugins.ChaosWorks.csproj
@@ -42,6 +42,7 @@
+
@@ -69,6 +70,7 @@
+