Added setup system. Changed reader and writer for texture atlas and nine patch to have image and serialized data be in same file. Some refactors occurred as well.

This commit is contained in:
Harrison Deng 2019-01-21 19:56:51 -06:00
parent fbf6c5d1aa
commit ea6b3cf9e3
18 changed files with 145 additions and 111 deletions

View File

@ -1,14 +1,26 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using System.IO;
namespace RecrownedAthenaeum.Pipeline.NinePatch
{
[ContentImporter(".9p", DisplayName = "Nine Patch Importer", DefaultProcessor = "NinePatchProcessor")]
internal class NinePatchImporter : ContentImporter<string>
internal class NinePatchImporter : ContentImporter<NinePatchImporter.Package>
{
public override string Import(string filename, ContentImporterContext context)
public override Package Import(string filename, ContentImporterContext context)
{
return File.ReadAllText(filename);
Package package;
package.ninePatchData = JsonConvert.DeserializeObject<NinePatchData>(File.ReadAllText(filename));
package.textureBytes = File.ReadAllBytes(package.ninePatchData.textureName);
return package;
}
internal struct Package
{
internal byte[] textureBytes;
internal NinePatchData ninePatchData;
}
}
}

View File

@ -1,17 +1,25 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using System.Text;
namespace RecrownedAthenaeum.Pipeline.NinePatch
{
[ContentImporter(DisplayName = "Nine Patch - RecrownedAthenaeum")]
class NinePatchProcessor : ContentProcessor<string, NinePatchData>
class NinePatchProcessor : ContentProcessor<NinePatchImporter.Package, NinePatchProcessor.Package>
{
public override NinePatchData Process(string input, ContentProcessorContext context)
public override Package Process(NinePatchImporter.Package input, ContentProcessorContext context)
{
NinePatchData ninePatchData = JsonConvert.DeserializeObject<NinePatchData>(input);
context.AddDependency(ninePatchData.textureName);
return ninePatchData;
Package package;
package.ninePatchDataBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(input.ninePatchData));
package.textureBytes = input.textureBytes;
return package;
}
internal struct Package
{
internal byte[] ninePatchDataBytes;
internal byte[] textureBytes;
}
}
}

View File

@ -6,16 +6,19 @@ using RecrownedAthenaeum.Data;
namespace RecrownedAthenaeum.Pipeline.NinePatch
{
[ContentTypeWriter]
class NinePatchWriter : ContentTypeWriter<NinePatchData>
class NinePatchWriter : ContentTypeWriter<NinePatchProcessor.Package>
{
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return "RecrownedAthenaeum.ContentReaders.NinePatchDataReader, RecrownedAthenaeum";
}
protected override void Write(ContentWriter output, NinePatchData value)
protected override void Write(ContentWriter output, NinePatchProcessor.Package value)
{
output.Write(JsonConvert.SerializeObject(value));
output.Write(value.textureBytes.Length);
output.Write(value.textureBytes);
output.Write(value.ninePatchDataBytes.Length);
output.Write(value.ninePatchDataBytes);
}
}
}

View File

@ -1,15 +1,25 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using System.IO;
using TImport = System.String;
namespace RecrownedAthenaeum.Pipeline.TextureAtlas
{
[ContentImporter(".tatlas", DisplayName = "Texture Atlas Importer", DefaultProcessor = "TextureAtlasProcessor")]
internal class TextureAtlasImporter : ContentImporter<TImport>
internal class TextureAtlasImporter : ContentImporter<TextureAtlasImporter.Package>
{
public override TImport Import(string filename, ContentImporterContext context)
public override Package Import(string filename, ContentImporterContext context)
{
return File.ReadAllText(filename);
Package package;
package.textureAtlasData = JsonConvert.DeserializeObject<TextureAtlasData>(File.ReadAllText(filename));
package.textureBytes = File.ReadAllBytes(package.textureAtlasData.textureName);
return package;
}
internal struct Package
{
internal TextureAtlasData textureAtlasData;
internal byte[] textureBytes;
}
}
}

View File

@ -1,17 +1,24 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using System.Text;
namespace RecrownedAthenaeum.Pipeline.TextureAtlas
{
[ContentProcessor(DisplayName = "Texture Atlas - RecrownedAthenaeum")]
class TextureAtlasProcessor : ContentProcessor<string, TextureAtlasData>
class TextureAtlasProcessor : ContentProcessor<TextureAtlasImporter.Package, TextureAtlasProcessor.Package>
{
public override TextureAtlasData Process(string input, ContentProcessorContext context)
public override Package Process(TextureAtlasImporter.Package input, ContentProcessorContext context)
{
TextureAtlasData textureAtlasData = JsonConvert.DeserializeObject<TextureAtlasData>(input);
context.AddDependency(textureAtlasData.textureName);
return textureAtlasData;
Package package;
package.textureBytes = input.textureBytes;
package.textureAtlasDataBytes = Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(input.textureAtlasData));
return package;
}
internal struct Package
{
public byte[] textureBytes;
public byte[] textureAtlasDataBytes;
}
}
}

View File

@ -1,21 +1,22 @@
using Microsoft.Xna.Framework.Content.Pipeline;
using Microsoft.Xna.Framework.Content.Pipeline.Serialization.Compiler;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
namespace RecrownedAthenaeum.Pipeline.TextureAtlas
{
[ContentTypeWriter]
class TextureAtlasWriter : ContentTypeWriter<TextureAtlasData>
class TextureAtlasWriter : ContentTypeWriter<TextureAtlasProcessor.Package>
{
public override string GetRuntimeReader(TargetPlatform targetPlatform)
{
return "RecrownedAthenaeum.ContentReaders.TextureAtlasDataReader, RecrownedAthenaeum";
}
protected override void Write(ContentWriter output, TextureAtlasData value)
protected override void Write(ContentWriter output, TextureAtlasProcessor.Package value)
{
output.Write(JsonConvert.SerializeObject(value));
output.Write(value.textureBytes.Length);
output.Write(value.textureBytes);
output.Write(value.textureAtlasDataBytes.Length);
output.Write(value.textureAtlasDataBytes);
}
}
}

View File

@ -24,15 +24,17 @@ namespace RecrownedAthenaeum.Camera
/// </summary>
public Matrix Matrix { get; private set; }
private GraphicsDevice graphicsDevice;
private GraphicsDevice graphicsDevice = Setup.graphicsDeviceManager.GraphicsDevice;
/// <summary>
/// Constructs 2D camera.
/// </summary>
/// <param name="graphicsDevice">The graphics device to use.</param>
public Camera2D(GraphicsDevice graphicsDevice)
/// <param name="graphicsDevice">The graphics device to use. Will use graphics device from <see cref="Setup"/>'s graphics device manager if this is null which it is by default.</param>
public Camera2D(GraphicsDevice graphicsDevice = null)
{
this.graphicsDevice = graphicsDevice;
if (graphicsDevice != null) this.graphicsDevice = graphicsDevice;
if (this.graphicsDevice == null) throw new ArgumentNullException("Graphics device can't be null in setup and argument. One must not be null for use.");
Zoom = 1f;
Position.X = this.graphicsDevice.Viewport.Width * 0.5f;
Position.Y = this.graphicsDevice.Viewport.Height * 0.5f;

View File

@ -1,15 +1,25 @@
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using RecrownedAthenaeum.SpecialTypes;
using System.IO;
using System.Text;
namespace RecrownedAthenaeum.ContentReaders
{
class NinePatchDataReader : ContentTypeReader<SpecialTypes.NinePatch>
class NinePatchDataReader : ContentTypeReader<NinePatch>
{
protected override SpecialTypes.NinePatch Read(ContentReader input, SpecialTypes.NinePatch existingInstance)
protected override NinePatch Read(ContentReader input, NinePatch existingInstance)
{
string serialized = input.ReadString();
return JsonConvert.DeserializeObject<SpecialTypes.NinePatch>(serialized);
Texture2D texture;
using (MemoryStream stream = new MemoryStream(input.ReadBytes(input.ReadInt32())))
{
texture = Texture2D.FromStream(Setup.graphicsDeviceManager.GraphicsDevice, stream);
}
NinePatchData ninePatchData = JsonConvert.DeserializeObject<NinePatchData>(Encoding.ASCII.GetString(input.ReadBytes(input.ReadInt32())));
NinePatch ninePatch = new NinePatch(texture, ninePatchData.left, ninePatchData.right, ninePatchData.bottom, ninePatchData.top);
return ninePatch;
}
}
}

View File

@ -4,6 +4,7 @@ using Newtonsoft.Json;
using RecrownedAthenaeum.Data;
using RecrownedAthenaeum.SpecialTypes;
using System.IO;
using System.Text;
namespace RecrownedAthenaeum.ContentReaders
{
@ -11,9 +12,14 @@ namespace RecrownedAthenaeum.ContentReaders
{
protected override TextureAtlas Read(ContentReader input, TextureAtlas existingInstance)
{
string serialized = input.ReadString();
TextureAtlasData atlasData = JsonConvert.DeserializeObject<TextureAtlasData>(serialized);
Texture2D atlasTexture = input.ContentManager.Load<Texture2D>(Path.GetFileNameWithoutExtension(atlasData.textureName));
TextureAtlasData atlasData;
Texture2D atlasTexture;
using (MemoryStream stream = new MemoryStream(input.ReadBytes(input.ReadInt32())))
{
atlasTexture = Texture2D.FromStream(Setup.graphicsDeviceManager.GraphicsDevice, stream);
}
string serialized = Encoding.ASCII.GetString(input.ReadBytes(input.ReadInt32()));
atlasData = JsonConvert.DeserializeObject<TextureAtlasData>(serialized);
TextureAtlas atlas = new TextureAtlas(atlasTexture, GenerateAtlasRegionsFromData(atlasData, atlasTexture));
return atlas;
@ -35,10 +41,9 @@ namespace RecrownedAthenaeum.ContentReaders
if (regionData.ninePatchData != null)
{
NinePatchData nPatchData = regionData.ninePatchData;
nPatch = new NinePatch(atlasTexture, nPatchData.left, nPatchData.right, nPatchData.bottom, nPatchData.bottom);
nPatch = new NinePatch(atlasTexture, nPatchData.left, nPatchData.right, nPatchData.bottom, nPatchData.bottom, regionData.bounds);
}
regions[regionID] = new TextureAtlas.Region(regionData.name, regionData.location, nPatch, atlasTexture);
regions[regionID] = new TextureAtlas.Region(regionData.name, regionData.bounds, nPatch, atlasTexture);
}
return regions;

View File

@ -39,7 +39,7 @@ namespace RecrownedAthenaeum.Data
/// <summary>
/// The location of the patch is designated by this rectangle.
/// </summary>
public Rectangle location;
public Rectangle bounds;
/// <summary>
/// The ninepatch information.
/// </summary>
@ -52,8 +52,8 @@ namespace RecrownedAthenaeum.Data
/// <param name="y">Y coordinate of the position in the patch.</param>
public void SetPosition(int x, int y)
{
location.X = x;
location.Y = y;
bounds.X = x;
bounds.Y = y;
}
/// <summary>
@ -63,8 +63,8 @@ namespace RecrownedAthenaeum.Data
/// <param name="height">Height of the region.</param>
public void SetSize(int width, int height)
{
location.Width = width;
location.Height = height;
bounds.Width = width;
bounds.Height = height;
}
/// <summary>

View File

@ -58,6 +58,7 @@
<Compile Include="ContentSystem\ContentResolvers\ResolutionContentResolver.cs" />
<Compile Include="ContentSystem\IContentPathModifier.cs" />
<Compile Include="ContentSystem\ContentResolvers\NormalContentResolver.cs" />
<Compile Include="Setup.cs" />
<Compile Include="SpecialTypes\ISpecialDrawable.cs" />
<Compile Include="SpecialTypes\NinePatch.cs" />
<Compile Include="SpecialTypes\Resolution.cs" />

View File

@ -20,19 +20,20 @@ namespace RecrownedAthenaeum.Render
BasicEffect basicEffect;
PrimitiveType primitiveType;
int verticesPerPrimitive;
GraphicsDevice graphicsDevice;
GraphicsDevice graphicsDevice = Setup.graphicsDeviceManager.GraphicsDevice;
bool began;
bool disposed;
/// <summary>
/// Creates a batch used to draw primitives.
/// </summary>
/// <param name="graphicsDevice">The current graphics device being used.</param>
/// <param name="camera">The current camera being used.</param>
/// <param name="graphicsDevice">The graphics device used to draw the primitives. Will be using <see cref="Setup"/>'s graphics device from graphics device manager if null. Default is null.</param>
/// <param name="verticesPerBatch">The amount of vertices every batch can hold before flushing. Default is 450. Should be changed to be the most optimal number if possible to prevent unnecessary resizing. Especially if using strip primitive types.</param>
public PrimitiveBatch(GraphicsDevice graphicsDevice, Camera2D camera, int verticesPerBatch = 500)
public PrimitiveBatch(Camera2D camera, GraphicsDevice graphicsDevice = null, int verticesPerBatch = 500)
{
this.graphicsDevice = graphicsDevice ?? throw new ArgumentNullException("Graphics device can't be null.");
if (graphicsDevice != null) this.graphicsDevice = graphicsDevice;
if (this.graphicsDevice == null) throw new ArgumentNullException("Graphics device can't be null in setup and argument. One must not be null for use.");
basicEffect = new BasicEffect(graphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.View = camera.Matrix;

View File

@ -1,6 +1,5 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
namespace RecrownedAthenaeum.Render
@ -8,10 +7,10 @@ namespace RecrownedAthenaeum.Render
/// <summary>
/// Renders rectangles using the <see cref="PrimitiveBatch"/>.
/// </summary>
public class RectangleRenderer : IDisposable
public class RectangleRenderer
{
/// <summary>
/// The <see cref="PrimitiveBatch"/> used.
/// The <see cref="PrimitiveBatch"/> used. Needs to be disposed.
/// </summary>
public readonly PrimitiveBatch primitiveBatch;
private bool disposed;
@ -27,16 +26,6 @@ namespace RecrownedAthenaeum.Render
this.primitiveBatch = primitiveBatch;
}
/// <summary>
/// Creates a rectangle renderer.
/// </summary>
/// <param name="graphicsDevice">The graphics device used to create the <see cref="PrimitiveBatch"/></param>
/// <param name="camera">The camera containing the matrix to be used for the transformations.</param>
public RectangleRenderer(GraphicsDevice graphicsDevice, Camera2D camera) : this(new PrimitiveBatch(graphicsDevice, camera, 4))
{
}
/// <summary>
/// Begins the render batch.
/// </summary>
@ -98,40 +87,5 @@ namespace RecrownedAthenaeum.Render
primitiveBatch.AddVertex(corners[3], color);
}
}
/// <summary>
/// Attempts to dispose of this object.
/// </summary>
public void Dispose()
{
if (disposed) throw new ObjectDisposedException(typeof(PrimitiveBatch).Name);
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// An overridable of disposable.
/// </summary>
/// <param name="disposing">Only true when called by user code dispose. Destructor calling this results in false.</param>
public virtual void Dispose(bool disposing)
{
disposed = true;
if (!disposed && disposing)
{
disposed = true;
if (primitiveBatch != null)
{
primitiveBatch.Dispose();
}
}
}
/// <summary>
/// Destructor.
/// </summary>
~RectangleRenderer ()
{
Dispose(false);
}
}
}

View File

@ -23,7 +23,7 @@ namespace RecrownedAthenaeum.ScreenSystem
/// Called when the first loading screen is done, and needs to show the landing screen.
/// </summary>
public event ShowFirstScreen ShowFirstScreenEvent;
private GraphicsDeviceManager graphics;
private GraphicsDeviceManager graphics = Setup.graphicsDeviceManager;
private Screen previousScreen;
private RenderTarget2D previousScreenRenderTarget;
private Screen currentScreen;
@ -63,11 +63,12 @@ namespace RecrownedAthenaeum.ScreenSystem
/// <summary>
/// Creates a screen manager that helps manage multiple screens and their transitions.
/// </summary>
/// <param name="graphicsDeviceManager">The graphics device manager to be used.</param>
/// <param name="camera">The camera to be used to perform the correct translations and transformations.</param>
public ScreenManager(GraphicsDeviceManager graphicsDeviceManager, Camera2D camera)
/// <param name="graphicsDeviceManager">The graphics device manager to be used.</param>
public ScreenManager(Camera2D camera, GraphicsDeviceManager graphicsDeviceManager = null)
{
this.graphics = graphicsDeviceManager;
if (graphicsDeviceManager != null) this.graphics = graphicsDeviceManager;
if (graphics == null) throw new ArgumentNullException("Graphics device manager argument cannot be null if setup's graphics device manager is also null.");
this.camera = camera;
}

View File

@ -0,0 +1,15 @@
using Microsoft.Xna.Framework;
namespace RecrownedAthenaeum
{
/// <summary>
/// All variables here should be for RecrownedAthenaeum to use when needed and thus eliminates unessecary passing.
/// </summary>
public static class Setup
{
/// <summary>
/// The graphics device that will be used by default.
/// </summary>
public static GraphicsDeviceManager graphicsDeviceManager;
}
}

View File

@ -28,10 +28,11 @@ namespace RecrownedAthenaeum.SpecialTypes
/// <param name="right">Right side.</param>
/// <param name="bottom">Bottom side.</param>
/// <param name="top">Top side.</param>
public NinePatch(Texture2D texture, int left, int right, int bottom, int top)
/// <param name="textureBounds">The dimensions and potentially the coordinates of the rectangle on an atlas. If left to default of null, will only be set to texture bounds.</param>
public NinePatch(Texture2D texture, int left, int right, int bottom, int top, Rectangle? textureBounds = null)
{
this.texture = texture;
textureRegion = texture.Bounds;
if (textureBounds.HasValue) textureRegion = textureBounds.Value; else textureRegion = texture.Bounds;
if (left + right >= textureRegion.Width) throw new ArgumentOutOfRangeException("a and b cannot be greater than or equal to the width of region.");
if (bottom + top >= textureRegion.Height) throw new ArgumentOutOfRangeException("c and d cannot be greater or equal to the height of the texture.");
this.left = left;

View File

@ -65,10 +65,11 @@ namespace RecrownedAthenaeum.SpecialTypes
/// Creates or obtains a previously created texture of a region.
/// </summary>
/// <param name="name">Name of region.</param>
/// <param name="graphicsDevice">graphics device to be used.</param>
/// <param name="graphicsDevice">graphics device to be used. Default is null and will resort to using graphics device from <see cref="Setup"/>'s graphics device manager.</param>
/// <returns>The texture from the region.</returns>
public Texture2D ObtainRegionAsTexture(string name, GraphicsDevice graphicsDevice)
public Texture2D ObtainRegionAsTexture(string name, GraphicsDevice graphicsDevice = null)
{
if (graphicsDevice == null) graphicsDevice = Setup.graphicsDeviceManager.GraphicsDevice;
return dictionaryOfRegions[name].AsTexture2D(graphicsDevice);
}
@ -174,15 +175,16 @@ namespace RecrownedAthenaeum.SpecialTypes
/// <summary>
/// Create or obtains a previously created texture of this region.
/// </summary>
/// <param name="graphicsDevice">The graphics device to use to create the texture.</param>
/// <param name="graphicsDevice">The graphics device to use to create the texture. Will use graphics device from <see cref="Setup"/>'s graphics device manager if left to null.</param>
/// <returns>The texture of the region.</returns>
public Texture2D AsTexture2D(GraphicsDevice graphicsDevice)
public Texture2D AsTexture2D(GraphicsDevice graphicsDevice = null)
{
if (Disposed) throw new ObjectDisposedException(GetType().Name);
if (regionTexture == null)
{
Color[] data = new Color[sourceRectangle.Width * sourceRectangle.Height];
if (graphicsDevice == null) graphicsDevice = Setup.graphicsDeviceManager.GraphicsDevice;
regionTexture = new Texture2D(graphicsDevice, sourceRectangle.Width, sourceRectangle.Height);
atlasTexture.GetData(0, sourceRectangle, data, 0, sourceRectangle.Width * sourceRectangle.Height);
regionTexture.SetData(data);

View File

@ -66,7 +66,7 @@ namespace RecrownedAthenaeum.UI.Skin
public ISkin Skin { get { return mergedSkin; } }
/// <summary>
/// The user loaded skin. Set by the skin loaded by calling <see cref="LoadSkin(GraphicsDevice, SkinData, string)"/>.
/// The user loaded skin. Set by the skin loaded by calling <see cref="LoadSkin(SkinData, string, GraphicsDevice)"/>.
/// </summary>
public ISkin loadedSkin { get { return mergedSkin.mainSkin; } private set { mergedSkin.mainSkin = value; } }
@ -106,11 +106,12 @@ namespace RecrownedAthenaeum.UI.Skin
/// <summary>
/// loads a skin asynchronously.
/// </summary>
/// <param name="graphicsDevice">Graphics device to use for texture creation.</param>
/// <param name="graphicsDevice">Graphics device to use for texture creation. Uses graphics device from <see cref="Setup"/>by default.</param>
/// <param name="skinData">The data to generate from.</param>
/// <param name="path">The path pointing to the file with the extension "<see cref="EXTENSION"/>".</param>
public void LoadSkin(GraphicsDevice graphicsDevice, SkinData skinData, string path)
public void LoadSkin(SkinData skinData, string path, GraphicsDevice graphicsDevice = null)
{
if (graphicsDevice == null) graphicsDevice = Setup.graphicsDeviceManager.GraphicsDevice;
action = Action.LOAD;
this.graphicsDevice = graphicsDevice;
this.selectedSkinPath = path;