diff --git a/MLEM/Textures/DataTextureAtlas.cs b/MLEM/Textures/DataTextureAtlas.cs
new file mode 100644
index 0000000..1c746da
--- /dev/null
+++ b/MLEM/Textures/DataTextureAtlas.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Text.RegularExpressions;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace MLEM.Textures {
+ ///
+ /// This class represents an atlas of objects which are loaded from a special texture atlas file.
+ /// To load a data texture atlas, you can use .
+ ///
+ public class DataTextureAtlas {
+
+ ///
+ /// The texture to use for this atlas
+ ///
+ public readonly Texture2D Texture;
+ ///
+ /// Returns the texture region with the given name.
+ ///
+ /// The region's name
+ public TextureRegion this[string name] => this.regions[name];
+ ///
+ /// Returns an enumerable of all of the s in this atlas.
+ ///
+ public IEnumerable Regions => this.regions.Values;
+
+ private readonly Dictionary regions = new Dictionary();
+
+ ///
+ /// Creates a new data texture atlas with the given texture and region amount.
+ ///
+ /// The texture to use for this atlas
+ public DataTextureAtlas(Texture2D texture) {
+ this.Texture = texture;
+ }
+
+ internal static DataTextureAtlas Load(ContentManager content, string texturePath, string infoPath, bool pivotRelative) {
+ var info = new FileInfo(Path.Combine(content.RootDirectory, infoPath ?? $"{texturePath}.atlas"));
+ string text;
+ using (var reader = info.OpenText())
+ text = reader.ReadToEnd();
+
+ var texture = content.Load(texturePath);
+ var atlas = new DataTextureAtlas(texture);
+
+ // parse each texture region: " loc piv "
+ const string regex = @"(.+)\W+loc\W+([0-9]+)\W+([0-9]+)\W+([0-9]+)\W+([0-9]+)\W+(?:piv\W+([0-9.]+)\W+([0-9.]+))?";
+ foreach (Match match in Regex.Matches(text, regex)) {
+ var name = match.Groups[1].Value.Trim();
+ var loc = new Rectangle(
+ int.Parse(match.Groups[2].Value), int.Parse(match.Groups[3].Value),
+ int.Parse(match.Groups[4].Value), int.Parse(match.Groups[5].Value));
+ var piv = Vector2.Zero;
+ if (match.Groups[6].Success) {
+ piv = new Vector2(
+ float.Parse(match.Groups[6].Value, CultureInfo.InvariantCulture) - (pivotRelative ? 0 : loc.X),
+ float.Parse(match.Groups[7].Value, CultureInfo.InvariantCulture) - (pivotRelative ? 0 : loc.Y));
+ }
+ atlas.regions.Add(name, new TextureRegion(texture, loc) {
+ PivotPixels = piv,
+ Name = name
+ });
+ }
+
+ return atlas;
+ }
+
+ }
+
+ ///
+ /// A set of extension methods for dealing with .
+ ///
+ public static class DataTextureAtlasExtensions {
+
+ ///
+ /// Loads a from the given texture and texture data file.
+ ///
+ /// The content manager to use for loading
+ /// The path to the texture file
+ /// The path, including extension, to the atlas info file, or null if ".atlas" should be used
+ /// If this value is true, then the pivot points passed in the info file will be relative to the coordinates of the texture region, not relative to the entire texture's origin.
+ /// A new data texture atlas with the given settings
+ public static DataTextureAtlas LoadTextureAtlas(this ContentManager content, string texturePath, string infoPath = null, bool pivotRelative = false) {
+ return DataTextureAtlas.Load(content, texturePath, infoPath, pivotRelative);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Sandbox/Content/Content.mgcb b/Sandbox/Content/Content.mgcb
index b3ff1d0..e4b5d48 100644
--- a/Sandbox/Content/Content.mgcb
+++ b/Sandbox/Content/Content.mgcb
@@ -41,6 +41,21 @@
#begin Test.json
/copy:Test.json
+#begin Textures/Furniture.atlas
+/copy:Textures/Furniture.atlas
+
+#begin Textures/Furniture.png
+/importer:TextureImporter
+/processor:TextureProcessor
+/processorParam:ColorKeyColor=255,0,255,255
+/processorParam:ColorKeyEnabled=True
+/processorParam:GenerateMipmaps=False
+/processorParam:PremultiplyAlpha=True
+/processorParam:ResizeToPowerOfTwo=False
+/processorParam:MakeSquare=False
+/processorParam:TextureFormat=Color
+/build:Textures/Furniture.png
+
#begin Tiled/Map.tmx
/importer:TiledMapImporter
/processor:TiledMapProcessor
diff --git a/Sandbox/Content/Textures/Furniture.atlas b/Sandbox/Content/Textures/Furniture.atlas
new file mode 100644
index 0000000..9bc74c8
--- /dev/null
+++ b/Sandbox/Content/Textures/Furniture.atlas
@@ -0,0 +1,16 @@
+SimpleDeskUp
+loc 0 0 48 32
+piv 16 16
+SimpleDeskRight
+loc 48 0 48 32
+piv 80 16
+
+Plant
+loc 96 0 16 32
+
+LongTableUp
+loc 0 32 64 48
+piv 16 48
+LongTableRight
+loc 64 32 64 48
+piv 112 48
\ No newline at end of file
diff --git a/Sandbox/Content/Textures/Furniture.png b/Sandbox/Content/Textures/Furniture.png
new file mode 100644
index 0000000..2aae963
Binary files /dev/null and b/Sandbox/Content/Textures/Furniture.png differ
diff --git a/Sandbox/GameImpl.cs b/Sandbox/GameImpl.cs
index c811dc1..bb9e9a1 100644
--- a/Sandbox/GameImpl.cs
+++ b/Sandbox/GameImpl.cs
@@ -143,6 +143,11 @@ namespace Sandbox {
var region = new TextureRegion(round) {Pivot = new Vector2(0.5F)};
var region2 = new TextureRegion(round);
+ var atlas = this.Content.LoadTextureAtlas("Textures/Furniture");
+ foreach (var r in atlas.Regions) {
+ Console.WriteLine(r.Name + ": " + r.U + " " + r.V + " " + r.Width + " " + r.Height + " " + r.PivotPixels);
+ }
+
this.OnDraw += (g, time) => {
this.SpriteBatch.Begin(samplerState: SamplerState.PointClamp);
//this.SpriteBatch.Draw(square, new Rectangle(10, 10, 400, 400), Color.White);
diff --git a/Sandbox/Sandbox.csproj b/Sandbox/Sandbox.csproj
index 45565c1..5ef7fce 100644
--- a/Sandbox/Sandbox.csproj
+++ b/Sandbox/Sandbox.csproj
@@ -25,6 +25,12 @@
PreserveNewest
+
+ PreserveNewest
+
+
+ PreserveNewest
+