From 4136b1ca22e732ba22a115ce5b138de395ad65da Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Wed, 5 Dec 2018 02:28:09 -0600 Subject: [PATCH] untested texture atlas pipeline system complete. --- ...{NinePatchTemplate.cs => NinePatchData.cs} | 2 +- .../RecrownedAthenaeum.Pipeline.csproj | 10 +--- ...reAtlasTemplate.cs => TextureAtlasData.cs} | 7 ++- .../TextureAtlas/TextureAtlasImporter.cs | 17 +++--- .../TextureAtlas/TextureAtlasProcessor.cs | 22 +++++-- .../TextureAtlas/TextureAtlasWriter.cs | 10 ++-- RecrownedAthenaeum/DataTypes/NinePatch.cs | 58 ++++++++++++------ RecrownedAthenaeum/DataTypes/TextureAtlas.cs | 21 +++++-- .../Pipeline/TextureAtlasDataReader.cs | 59 +++++++++++++++++++ RecrownedAthenaeum/RecrownedAthenaeum.csproj | 7 +++ 10 files changed, 162 insertions(+), 51 deletions(-) rename RecrownedAthenaeum.Pipeline/NinePatch/{NinePatchTemplate.cs => NinePatchData.cs} (89%) rename RecrownedAthenaeum.Pipeline/TextureAtlas/{TextureAtlasTemplate.cs => TextureAtlasData.cs} (75%) create mode 100644 RecrownedAthenaeum/Pipeline/TextureAtlasDataReader.cs diff --git a/RecrownedAthenaeum.Pipeline/NinePatch/NinePatchTemplate.cs b/RecrownedAthenaeum.Pipeline/NinePatch/NinePatchData.cs similarity index 89% rename from RecrownedAthenaeum.Pipeline/NinePatch/NinePatchTemplate.cs rename to RecrownedAthenaeum.Pipeline/NinePatch/NinePatchData.cs index 8188c55..c64ac92 100644 --- a/RecrownedAthenaeum.Pipeline/NinePatch/NinePatchTemplate.cs +++ b/RecrownedAthenaeum.Pipeline/NinePatch/NinePatchData.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace RecrownedAthenaeum.Pipeline.NinePatch { - class NinePatchFile + public class NinePatchData { public string name; public string bounds; diff --git a/RecrownedAthenaeum.Pipeline/RecrownedAthenaeum.Pipeline.csproj b/RecrownedAthenaeum.Pipeline/RecrownedAthenaeum.Pipeline.csproj index 9b00e91..b81b0bc 100644 --- a/RecrownedAthenaeum.Pipeline/RecrownedAthenaeum.Pipeline.csproj +++ b/RecrownedAthenaeum.Pipeline/RecrownedAthenaeum.Pipeline.csproj @@ -50,18 +50,12 @@ - + - - - - - {95a926dc-1482-4368-91da-8d30ac04740a} - RecrownedAthenaeum - + diff --git a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasTemplate.cs b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasData.cs similarity index 75% rename from RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasTemplate.cs rename to RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasData.cs index 42cd62d..447ec23 100644 --- a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasTemplate.cs +++ b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasData.cs @@ -1,4 +1,6 @@ using Microsoft.Xna.Framework; +using Newtonsoft.Json; +using RecrownedAthenaeum.Pipeline.NinePatch; using System; using System.Collections.Generic; using System.Linq; @@ -8,15 +10,16 @@ using System.Xml.Serialization; namespace RecrownedAthenaeum.Pipeline.TextureAtlas { - public class TextureAtlasFile + public class TextureAtlasData { - public string textureName; public TextureAtlasRegion[] regions; + public string textureName; public class TextureAtlasRegion { public string name; public Rectangle location; + public NinePatchData ninePatchData; } } } diff --git a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasImporter.cs b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasImporter.cs index 8ccd0eb..c687e1c 100644 --- a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasImporter.cs +++ b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasImporter.cs @@ -1,6 +1,6 @@ using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Graphics; -using RecrownedAthenaeum.DataTypes; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -11,15 +11,16 @@ using System.Xml.Serialization; namespace RecrownedAthenaeum.Pipeline.TextureAtlas { - internal class TextureAtlasImporter : ContentImporter + [ContentImporter(".atlas", DisplayName = "Texture Atlas Importer")] + internal class TextureAtlasImporter : ContentImporter { - public override TextureAtlasFile Import(string filename, ContentImporterContext context) + public override TextureAtlasData Import(string filename, ContentImporterContext context) { - StreamReader stream = new StreamReader(filename); - XmlSerializer serializer = new XmlSerializer(typeof(TextureAtlasFile)); - TextureAtlasFile atlas = (TextureAtlasFile)serializer.Deserialize(stream); - context.AddDependency(atlas.textureName); - stream.Dispose(); + TextureAtlasData atlas; + using (StreamReader stream = new StreamReader(filename)) + { + atlas = JsonConvert.DeserializeObject(stream.ReadToEnd()); + } return atlas; } } diff --git a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasProcessor.cs b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasProcessor.cs index 840776d..bf18fda 100644 --- a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasProcessor.cs +++ b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasProcessor.cs @@ -1,21 +1,35 @@ using Microsoft.Xna.Framework.Content.Pipeline; using Microsoft.Xna.Framework.Graphics; -using RecrownedAthenaeum.DataTypes; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; +using System.IO.Compression; using System.Linq; using System.Text; using System.Threading.Tasks; namespace RecrownedAthenaeum.Pipeline.TextureAtlas { - class TextureAtlasProcessor : ContentProcessor + [ContentProcessor(DisplayName = "Texture Atlas Processor")] + class TextureAtlasProcessor : ContentProcessor { - public override TextureAtlasFile Process(TextureAtlasFile input, ContentProcessorContext context) + public override byte[] Process(TextureAtlasData input, ContentProcessorContext context) { - return input; + string serialized = JsonConvert.SerializeObject(input); + byte[] bytes = Encoding.UTF8.GetBytes(serialized); + + MemoryStream outStream = new MemoryStream(); + GZipStream gZStream = new GZipStream(outStream, CompressionLevel.Optimal); + + gZStream.Write(bytes, 0, bytes.Length); + + byte[] compressed = outStream.ToArray(); + + gZStream.Dispose(); + outStream.Dispose(); + return compressed; } } } diff --git a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasWriter.cs b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasWriter.cs index e807e09..0ffb60c 100644 --- a/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasWriter.cs +++ b/RecrownedAthenaeum.Pipeline/TextureAtlas/TextureAtlasWriter.cs @@ -8,16 +8,18 @@ using System.Threading.Tasks; namespace RecrownedAthenaeum.Pipeline.TextureAtlas { - class TextureAtlasWriter : ContentTypeWriter + [ContentTypeWriter] + class TextureAtlasWriter : ContentTypeWriter { public override string GetRuntimeReader(TargetPlatform targetPlatform) { - throw new NotImplementedException(); + return "RecrownedAthenaeum.Pipeline, TextureAtlasDataReader"; } - protected override void Write(ContentWriter output, TextureAtlasFile value) + protected override void Write(ContentWriter output, byte[] value) { - throw new NotImplementedException(); + output.Write(value.Length); + output.Write(value); } } } diff --git a/RecrownedAthenaeum/DataTypes/NinePatch.cs b/RecrownedAthenaeum/DataTypes/NinePatch.cs index 0373113..c5116b7 100644 --- a/RecrownedAthenaeum/DataTypes/NinePatch.cs +++ b/RecrownedAthenaeum/DataTypes/NinePatch.cs @@ -11,18 +11,16 @@ namespace RecrownedAthenaeum.DataTypes { public class NinePatch { - [XmlIgnore] public Color color; - - [XmlIgnore] + public Rectangle textureRegion; + readonly TextureAtlas.TextureAtlasRegion region; readonly Texture2D texture; - readonly int a, b, c, d; /// /// A nine patch object. /// - /// Texture used for the nine patch. Dimensions must be greater than their sum border counter parts. + /// Texture used for the nine patch. Dimensions must be greater than their sum border counter parts. If used as part of texture atlas, the texture should be the texture of the entire atlas. /// Left side. /// Right side. /// Bottom side. @@ -30,8 +28,9 @@ namespace RecrownedAthenaeum.DataTypes public NinePatch(Texture2D texture, int a, int b, int c, int d) { this.texture = texture; - if (a + b >= texture.Width) throw new ArgumentOutOfRangeException("a and b cannot be greater than or equal to the width of texture."); - if (c + d >= texture.Height) throw new ArgumentOutOfRangeException("c and d cannot be greater or equal to the height of the texture."); + textureRegion = texture.Bounds; + if (a + b >= textureRegion.Width) throw new ArgumentOutOfRangeException("a and b cannot be greater than or equal to the width of region."); + if (c + d >= textureRegion.Height) throw new ArgumentOutOfRangeException("c and d cannot be greater or equal to the height of the texture."); this.a = a; this.b = b; this.c = c; @@ -42,6 +41,8 @@ namespace RecrownedAthenaeum.DataTypes public void Draw(SpriteBatch batch, Rectangle destination) { + + Rectangle sourceRectangle; Rectangle drawnRectangle; @@ -56,6 +57,9 @@ namespace RecrownedAthenaeum.DataTypes sourceRectangle.Width = a; sourceRectangle.Height = c; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; + batch.Draw(texture, drawnRectangle, sourceRectangle, color); //2x1 @@ -66,8 +70,10 @@ namespace RecrownedAthenaeum.DataTypes sourceRectangle.X = a; sourceRectangle.Y = 0; - sourceRectangle.Width = texture.Width - a - b; + sourceRectangle.Width = textureRegion.Width - a - b; sourceRectangle.Height = c; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -77,10 +83,12 @@ namespace RecrownedAthenaeum.DataTypes drawnRectangle.Width = b; drawnRectangle.Height = c; - sourceRectangle.X = texture.Width - b; + sourceRectangle.X = textureRegion.Width - b; sourceRectangle.Y = 0; sourceRectangle.Width = b; sourceRectangle.Height = c; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -93,7 +101,9 @@ namespace RecrownedAthenaeum.DataTypes sourceRectangle.X = 0; sourceRectangle.Y = c; sourceRectangle.Width = a; - sourceRectangle.Height = texture.Height - c - d; + sourceRectangle.Height = textureRegion.Height - c - d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -105,8 +115,10 @@ namespace RecrownedAthenaeum.DataTypes sourceRectangle.X = a; sourceRectangle.Y = c; - sourceRectangle.Width = texture.Width - a - b; - sourceRectangle.Height = texture.Height - c - d; + sourceRectangle.Width = textureRegion.Width - a - b; + sourceRectangle.Height = textureRegion.Height - c - d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -116,10 +128,12 @@ namespace RecrownedAthenaeum.DataTypes drawnRectangle.Width = b; drawnRectangle.Height = destination.Height - c - d; - sourceRectangle.X = texture.Width - b; + sourceRectangle.X = textureRegion.Width - b; sourceRectangle.Y = c; sourceRectangle.Width = b; - sourceRectangle.Height = texture.Height - c - d; + sourceRectangle.Height = textureRegion.Height - c - d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -130,9 +144,11 @@ namespace RecrownedAthenaeum.DataTypes drawnRectangle.Height = d; sourceRectangle.X = a; - sourceRectangle.Y = texture.Height - d; + sourceRectangle.Y = textureRegion.Height - d; sourceRectangle.Width = a; sourceRectangle.Height = d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -143,9 +159,11 @@ namespace RecrownedAthenaeum.DataTypes drawnRectangle.Height = d; sourceRectangle.X = a; - sourceRectangle.Y = texture.Height - d; - sourceRectangle.Width = texture.Width - a - b; + sourceRectangle.Y = textureRegion.Height - d; + sourceRectangle.Width = textureRegion.Width - a - b; sourceRectangle.Height = d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); @@ -155,10 +173,12 @@ namespace RecrownedAthenaeum.DataTypes drawnRectangle.Width = b; drawnRectangle.Height = d; - sourceRectangle.X = texture.Width - b; - sourceRectangle.Y = texture.Height - d; + sourceRectangle.X = textureRegion.Width - b; + sourceRectangle.Y = textureRegion.Height - d; sourceRectangle.Width = b; sourceRectangle.Height = d; + sourceRectangle.X += textureRegion.X; + sourceRectangle.Y += textureRegion.Y; batch.Draw(texture, drawnRectangle, sourceRectangle, color); } diff --git a/RecrownedAthenaeum/DataTypes/TextureAtlas.cs b/RecrownedAthenaeum/DataTypes/TextureAtlas.cs index 1caf261..c421b32 100644 --- a/RecrownedAthenaeum/DataTypes/TextureAtlas.cs +++ b/RecrownedAthenaeum/DataTypes/TextureAtlas.cs @@ -1,5 +1,6 @@ using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; +using Newtonsoft.Json; using RecrownedAthenaeum.DataTypes; using System; using System.Collections.Generic; @@ -12,7 +13,9 @@ namespace RecrownedAthenaeum.DataTypes { public class TextureAtlas { + [JsonIgnore] private Texture2D texture; + private Dictionary dictionaryOfRegions = new Dictionary(); public TextureAtlas(Texture2D texture, TextureAtlasRegion[] regions) @@ -24,9 +27,15 @@ namespace RecrownedAthenaeum.DataTypes } } + public TextureAtlas(Texture2D texture, Dictionary dictionaryOfRegions) + { + this.texture = texture; + this.dictionaryOfRegions = dictionaryOfRegions; + } + public void Draw(string name, SpriteBatch batch, Rectangle destination, Color color, float rotation = 0, Vector2 origin = new Vector2()) { - dictionaryOfRegions[name].Draw(batch, destination, texture, color, rotation, origin); + dictionaryOfRegions[name].Draw(batch, destination, color, rotation, origin); } @@ -38,20 +47,22 @@ namespace RecrownedAthenaeum.DataTypes public class TextureAtlasRegion : IComparable, IDisposable { public readonly string name; - readonly Rectangle sourceRectangle; + public readonly Rectangle sourceRectangle; readonly NinePatch ninepatch; + Texture2D atlasTexture; Texture2D regionTexture; - public TextureAtlasRegion(string name, Rectangle source, NinePatch ninePatch) + public TextureAtlasRegion(string name, Rectangle source, NinePatch ninePatch, Texture2D atlasTexture) { + this.atlasTexture = atlasTexture; this.name = name; this.sourceRectangle = source; this.ninepatch = ninePatch; } - public void Draw(SpriteBatch batch, Rectangle destination, Texture2D fromTexture, Color color, float rotation, Vector2 origin) + public void Draw(SpriteBatch batch, Rectangle destination, Color color, float rotation, Vector2 origin) { - batch.Draw(fromTexture, destination, sourceRectangle, color, rotation, origin, SpriteEffects.None, 0f); + batch.Draw(atlasTexture, destination, sourceRectangle, color, rotation, origin, SpriteEffects.None, 0f); } public Texture2D AsTexture2D(GraphicsDevice graphicsDevice, Texture2D textureAtlas) diff --git a/RecrownedAthenaeum/Pipeline/TextureAtlasDataReader.cs b/RecrownedAthenaeum/Pipeline/TextureAtlasDataReader.cs new file mode 100644 index 0000000..1d05c1a --- /dev/null +++ b/RecrownedAthenaeum/Pipeline/TextureAtlasDataReader.cs @@ -0,0 +1,59 @@ +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Newtonsoft.Json; +using RecrownedAthenaeum.DataTypes; +using RecrownedAthenaeum.Pipeline.NinePatch; +using RecrownedAthenaeum.Pipeline.TextureAtlas; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace RecrownedAthenaeum.Pipeline +{ + class TextureAtlasDataReader : ContentTypeReader + { + protected override DataTypes.TextureAtlas Read(ContentReader input, DataTypes.TextureAtlas existingInstance) + { + int length = input.ReadInt32(); + byte[] compressedBytes = input.ReadBytes(length); + byte[] decompressedBytes; + using (MemoryStream inStream = new MemoryStream(compressedBytes)) + { + using (GZipStream gZStream = new GZipStream(inStream, CompressionLevel.Optimal)) + { + using (MemoryStream outStream = new MemoryStream()) + { + gZStream.CopyTo(outStream); + decompressedBytes = outStream.ToArray(); + } + } + } + TextureAtlasData atlasData = JsonConvert.DeserializeObject(Encoding.UTF8.GetString(decompressedBytes)); + + DataTypes.TextureAtlas atlas; + Texture2D atlasTexture = input.ContentManager.Load(atlasData.textureName); + DataTypes.TextureAtlas.TextureAtlasRegion[] regions = new DataTypes.TextureAtlas.TextureAtlasRegion[atlasData.regions.Length]; + + for (int regionID = 0; regionID < regions.Length; regionID++) + { + TextureAtlasData.TextureAtlasRegion regionData = atlasData.regions[regionID]; + DataTypes.NinePatch nPatch = null; + if (regionData.ninePatchData != null) + { + NinePatchData nPatchData = regionData.ninePatchData; + nPatch = new DataTypes.NinePatch(atlasTexture, nPatchData.a, nPatchData.b, nPatchData.c, nPatchData.d); + } + + regions[regionID] = new DataTypes.TextureAtlas.TextureAtlasRegion(regionData.name, regionData.location, nPatch, atlasTexture); + } + + atlas = new DataTypes.TextureAtlas(atlasTexture, regions); + + return atlas; + } + } +} diff --git a/RecrownedAthenaeum/RecrownedAthenaeum.csproj b/RecrownedAthenaeum/RecrownedAthenaeum.csproj index 380b028..01ffe12 100644 --- a/RecrownedAthenaeum/RecrownedAthenaeum.csproj +++ b/RecrownedAthenaeum/RecrownedAthenaeum.csproj @@ -65,6 +65,7 @@ + @@ -91,5 +92,11 @@ + + + {b38f9812-b1d1-4bfe-89ee-fc4dd4ebaa3f} + RecrownedAthenaeum.Pipeline + + \ No newline at end of file