From ea8f96d8777b64992e5783f19674250b97528bb7 Mon Sep 17 00:00:00 2001 From: Harrison Deng Date: Sun, 20 Jan 2019 01:08:38 -0600 Subject: [PATCH] Progress on skin system, added skin stack. --- .../SpecialTypes/TextureAtlas.cs | 32 ++-- .../UI/Modular/Modules/Interactive/Button.cs | 10 +- .../Modular/Modules/Interactive/TextButton.cs | 7 +- RecrownedAthenaeum/UI/Modular/Modules/Text.cs | 11 +- .../Definitions/TextButtonSkinDefinition.cs | 5 - .../UI/Skin/Definitions/TextSkinDefinition.cs | 4 +- RecrownedAthenaeum/UI/Skin/ISkin.cs | 76 ++++++++++ RecrownedAthenaeum/UI/Skin/Skin.cs | 121 ++++++++++++--- RecrownedAthenaeum/UI/Skin/SkinManager.cs | 53 ++++++- RecrownedAthenaeum/UI/Skin/SkinStack.cs | 138 ++++++++++++++++++ 10 files changed, 393 insertions(+), 64 deletions(-) create mode 100644 RecrownedAthenaeum/UI/Skin/ISkin.cs create mode 100644 RecrownedAthenaeum/UI/Skin/SkinStack.cs diff --git a/RecrownedAthenaeum/SpecialTypes/TextureAtlas.cs b/RecrownedAthenaeum/SpecialTypes/TextureAtlas.cs index 3673909..b01405b 100644 --- a/RecrownedAthenaeum/SpecialTypes/TextureAtlas.cs +++ b/RecrownedAthenaeum/SpecialTypes/TextureAtlas.cs @@ -14,13 +14,13 @@ namespace RecrownedAthenaeum.SpecialTypes private Texture2D texture; private bool disposed; private Dictionary dictionaryOfRegions = new Dictionary(); - + /// /// Given a name, can return a . /// /// Name of to obtain. /// based off name. - public Region this[string name] { get { if (name != null && dictionaryOfRegions.ContainsKey(name)) return dictionaryOfRegions[name]; else return null; } } + public Region this[string name] { get { if (name != null && dictionaryOfRegions.ContainsKey(name)) return dictionaryOfRegions[name]; else throw new KeyNotFoundException("Given key \"" + name + "\" does not exist."); } } /// /// Creates a texture atlas with given main texture as well as an array of to represent locations of which textures reside within the atlas. Region names will be used to refer to the regions within the dictionary. @@ -92,7 +92,12 @@ namespace RecrownedAthenaeum.SpecialTypes texture.Dispose(); for (int i = 0; i < dictionaryOfRegions.Count; i++) { - dictionaryOfRegions.ElementAt(i).Value.Dispose(); + Region region = dictionaryOfRegions.ElementAt(i).Value; + + if (!region.Disposed) + { + dictionaryOfRegions.ElementAt(i).Value.Dispose(); + } } dictionaryOfRegions.Clear(); } @@ -123,7 +128,11 @@ namespace RecrownedAthenaeum.SpecialTypes readonly NinePatch ninepatch; Texture2D atlasTexture; Texture2D regionTexture; - private bool disposed; + + /// + /// If region has already been disposed. + /// + public bool Disposed { get; private set; } /// /// A specified region in a texture atlas. @@ -150,12 +159,13 @@ namespace RecrownedAthenaeum.SpecialTypes /// The origin of the drawing. Ignored if is a 9patch. public void Draw(SpriteBatch batch, Rectangle destination, Color color, float rotation = 0, Vector2 origin = default(Vector2)) { - if (disposed) throw new ObjectDisposedException(GetType().Name); + if (Disposed) throw new ObjectDisposedException(GetType().Name); if (ninepatch != null) { ninepatch.Draw(batch, destination); - } else + } + else { batch.Draw(atlasTexture, destination, sourceRectangle, color, rotation, origin, SpriteEffects.None, 0f); } @@ -168,7 +178,7 @@ namespace RecrownedAthenaeum.SpecialTypes /// The texture of the region. public Texture2D AsTexture2D(GraphicsDevice graphicsDevice) { - if (disposed) throw new ObjectDisposedException(GetType().Name); + if (Disposed) throw new ObjectDisposedException(GetType().Name); if (regionTexture == null) { @@ -195,7 +205,7 @@ namespace RecrownedAthenaeum.SpecialTypes /// public void Dispose() { - if (disposed) throw new ObjectDisposedException(GetType().Name); + if (Disposed) throw new ObjectDisposedException(GetType().Name); Dispose(true); GC.SuppressFinalize(this); } @@ -206,13 +216,13 @@ namespace RecrownedAthenaeum.SpecialTypes /// Whether or not this was a user made call. public virtual void Dispose(bool disposing) { - if (disposing && !disposed) + if (disposing && !Disposed) { regionTexture?.Dispose(); } - disposed = true; + Disposed = true; } - + /// /// Destructor. /// diff --git a/RecrownedAthenaeum/UI/Modular/Modules/Interactive/Button.cs b/RecrownedAthenaeum/UI/Modular/Modules/Interactive/Button.cs index d39a3bb..d5d35a9 100644 --- a/RecrownedAthenaeum/UI/Modular/Modules/Interactive/Button.cs +++ b/RecrownedAthenaeum/UI/Modular/Modules/Interactive/Button.cs @@ -55,11 +55,11 @@ namespace RecrownedAthenaeum.UI.Modular.Modules.Interactive /// The name of the definition in the skin. Can be null to select the default. public Button(Skin.Skin skin, string definitionName = null) { - this.skinDefinition = skin.ObtainDefinition(definitionName, GetType()); - downTexture = skin.textureAtlas[skinDefinition.downRegion]; - upTexture = skin.textureAtlas[skinDefinition.upRegion]; - disabledTexture = skin.textureAtlas[skinDefinition.disabledRegion]; - highlightedTexture = skin.textureAtlas[skinDefinition.selectedRegion]; + skinDefinition = skin.ObtainDefinition(definitionName, GetType()); + downTexture = skin.GetTextureAtlasRegion(skinDefinition.downRegion); + upTexture = skin.GetTextureAtlasRegion(skinDefinition.upRegion); + disabledTexture = skin.GetTextureAtlasRegion(skinDefinition.disabledRegion); + highlightedTexture = skin.GetTextureAtlasRegion(skinDefinition.selectedRegion); } /// diff --git a/RecrownedAthenaeum/UI/Modular/Modules/Interactive/TextButton.cs b/RecrownedAthenaeum/UI/Modular/Modules/Interactive/TextButton.cs index 0c06afb..9ea7bad 100644 --- a/RecrownedAthenaeum/UI/Modular/Modules/Interactive/TextButton.cs +++ b/RecrownedAthenaeum/UI/Modular/Modules/Interactive/TextButton.cs @@ -38,13 +38,14 @@ namespace RecrownedAthenaeum.UI.Modular.Modules.Interactive /// Constructs a text button using a skin and definition. /// /// The text to display. + /// The font to be used. /// The skin to use. /// Name of the definition for this type in the skin given. - public TextButton(string text, Skin.Skin skin, string definitionName = null) : base(skin, definitionName) + public TextButton(string text, SpriteFont font, Skin.Skin skin, string definitionName = null) : base(skin, definitionName) { TextButtonSkinDefinition skinDefinition = skin.ObtainDefinition(definitionName, GetType()); - this.text = new Text(skin.fonts[skinDefinition.fontName], text); - FontColor = skin.colors[skinDefinition.fontColor]; + this.text = new Text(font, text); + FontColor = skin.GetColor(skinDefinition.fontColor); } /// diff --git a/RecrownedAthenaeum/UI/Modular/Modules/Text.cs b/RecrownedAthenaeum/UI/Modular/Modules/Text.cs index 2e8ea31..cacd1a1 100644 --- a/RecrownedAthenaeum/UI/Modular/Modules/Text.cs +++ b/RecrownedAthenaeum/UI/Modular/Modules/Text.cs @@ -57,13 +57,14 @@ namespace RecrownedAthenaeum.UI.Modular.Modules /// /// Creates a UI text object /// - /// - /// - /// - public Text(Skin.Skin skin, string skinDefinitionName = null, string content = null) : this(skin.fonts[skin.ObtainDefinition(skinDefinitionName, typeof(Text)).font]) + /// The skin to be used. + /// The name of the skin's definition to use of a . + /// The font to be used. + /// The string of text to be displayed. + public Text(Skin.Skin skin, SpriteFont font, string skinDefinitionName = null, string content = null) : this(font, content) { skinDefinition = skin.ObtainDefinition(skinDefinitionName, GetType()); - color = skin.colors[skinDefinition.color]; + color = skin.GetColor(skinDefinition.color); } /// diff --git a/RecrownedAthenaeum/UI/Skin/Definitions/TextButtonSkinDefinition.cs b/RecrownedAthenaeum/UI/Skin/Definitions/TextButtonSkinDefinition.cs index cf22224..8490d49 100644 --- a/RecrownedAthenaeum/UI/Skin/Definitions/TextButtonSkinDefinition.cs +++ b/RecrownedAthenaeum/UI/Skin/Definitions/TextButtonSkinDefinition.cs @@ -8,11 +8,6 @@ namespace RecrownedAthenaeum.UI.Skin.Definitions /// public class TextButtonSkinDefinition : ButtonSkinDefinition { - /// - /// Name of font from the skin to use. - /// - public string fontName; - /// /// Name of color from the skin to use for the font. /// diff --git a/RecrownedAthenaeum/UI/Skin/Definitions/TextSkinDefinition.cs b/RecrownedAthenaeum/UI/Skin/Definitions/TextSkinDefinition.cs index 435d58b..f9f3878 100644 --- a/RecrownedAthenaeum/UI/Skin/Definitions/TextSkinDefinition.cs +++ b/RecrownedAthenaeum/UI/Skin/Definitions/TextSkinDefinition.cs @@ -5,13 +5,11 @@ namespace RecrownedAthenaeum.UI.Skin.Definitions { class TextSkinDefinition : ISkinDefinitionData { - public string font; public string color; public Type UIModuleType { get { return typeof(Text); } } - public TextSkinDefinition(string font, string color) + public TextSkinDefinition(string color) { - this.font = font; this.color = color; } } diff --git a/RecrownedAthenaeum/UI/Skin/ISkin.cs b/RecrownedAthenaeum/UI/Skin/ISkin.cs new file mode 100644 index 0000000..268bb55 --- /dev/null +++ b/RecrownedAthenaeum/UI/Skin/ISkin.cs @@ -0,0 +1,76 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using RecrownedAthenaeum.SpecialTypes; +using RecrownedAthenaeum.UI.Skin.Definitions; + +namespace RecrownedAthenaeum.UI.Skin +{ + /// + /// The output requirements of a skin. This allows for very customized skin systems if needed. + /// + public interface ISkin + { + /// + /// The texture for the cursor. + /// + Texture2D CursorTexture { get; } + + /// + /// Draws a region from the texture atlas. + /// + /// Region to draw. + /// The color to tint the region. + /// The batch to use. + /// The destination to draw to. + /// The rotation to use in radians. + /// The origin for the rotation. + void Draw(string regionName, string color, SpriteBatch batch, Rectangle destination, float rotation = 0, Vector2 origin = default(Vector2)); + + /// + /// Returns a with given name of defined color; + /// + /// Name of defined color. + /// The defined color based on the name given. + Color GetColor(string name); + + /// + /// Returns a with given name of region. + /// + /// Name of region. + /// The region corresponding to the name. + TextureAtlas.Region GetTextureAtlasRegion(string name); + + /// + /// Returns an of the given name and type. + /// + /// Name of definition of the + /// The UIModule the definition defines. + /// The interface for the definition. + ISkinDefinitionData ObtainDefinition(string definitionName, Type type); + + /// + /// Returns the default of the given parameters. + /// + /// The type of definition the default should be coming from. + /// The default definition for the given type. + ISkinDefinitionData ObtainDefinition(Type type); + + /// + /// Returns the proper definition for the given parameters or throws exception in the case the requested definition does not exist. + /// + /// Convenience to cast to the needed definition type. + /// The name of the definition. + /// UIModule type the definition defines. + /// The definition cast to T. + T ObtainDefinition(string definitionName, Type type) where T : ISkinDefinitionData; + + /// + /// Returns the default definition. + /// + /// Convenience to cast to T. + /// The type of the UIModule to retrieve the default from. + /// The default definition for the given type. + T ObtainDefinition(Type type) where T : ISkinDefinitionData; + } +} \ No newline at end of file diff --git a/RecrownedAthenaeum/UI/Skin/Skin.cs b/RecrownedAthenaeum/UI/Skin/Skin.cs index 78eed68..9d4f276 100644 --- a/RecrownedAthenaeum/UI/Skin/Skin.cs +++ b/RecrownedAthenaeum/UI/Skin/Skin.cs @@ -4,36 +4,65 @@ using RecrownedAthenaeum.SpecialTypes; using RecrownedAthenaeum.UI.Skin.Definitions; using System; using System.Collections.Generic; +using System.IO; namespace RecrownedAthenaeum.UI.Skin { /// /// A skin is used to group a theme which can then be applied to the UI via the use of modules. /// - public class Skin + public class Skin : IDisposable, ISkin { /// - /// Texture atlas containing the skins textures. + /// Whether or not this skin is completed being built and thus ready to use. /// - public readonly TextureAtlas textureAtlas; - /// - /// Colors stored in this skin. - /// - public readonly Dictionary colors; + public bool Laminated { get; private set; } + private bool disposed; + + private TextureAtlas textureAtlas; + + Dictionary colors; Dictionary> definitions; + /// + /// The texture for the cursor. + /// + public virtual Texture2D CursorTexture { get; private set; } + /// /// Creates a basic unfilled skin. /// /// The texture atlas to use for this skin. - public Skin(TextureAtlas textureAtlas) + /// The texture the cursor will be. + public Skin(TextureAtlas textureAtlas, Texture2D cursorTexture) { this.textureAtlas = textureAtlas; + this.CursorTexture = cursorTexture; colors = new Dictionary(); definitions = new Dictionary>(); } + /// + /// Returns a with given name of region. + /// + /// Name of region. + /// The region corresponding to the name. + public virtual TextureAtlas.Region GetTextureAtlasRegion(string name) + { + return textureAtlas[name]; + } + + /// + /// Returns a with given name of defined color; + /// + /// Name of defined color. + /// The defined color based on the name given. + public virtual Color GetColor(string name) + { + return colors[name]; + } + /// /// Draws a region from the texture atlas. /// @@ -43,8 +72,9 @@ namespace RecrownedAthenaeum.UI.Skin /// The destination to draw to. /// The rotation to use in radians. /// The origin for the rotation. - public void Draw(string regionName, string color, SpriteBatch batch, Rectangle destination, float rotation = 0, Vector2 origin = default(Vector2)) + public virtual void Draw(string regionName, string color, SpriteBatch batch, Rectangle destination, float rotation = 0, Vector2 origin = default(Vector2)) { + if (disposed) throw new ObjectDisposedException(GetType().Name); textureAtlas.Draw(regionName, batch, destination, colors[color], rotation, origin); } @@ -54,10 +84,12 @@ namespace RecrownedAthenaeum.UI.Skin /// Name of definition of the /// The UIModule the definition defines. /// The interface for the definition. - public ISkinDefinitionData ObtainDefinition(string definitionName, Type type) + public virtual ISkinDefinitionData ObtainDefinition(string definitionName, Type type) { + if (disposed) throw new ObjectDisposedException(GetType().Name); + if (!Laminated) throw new InvalidOperationException("Skin has yet to be laminated yet."); if (definitionName == null) definitionName = "default"; - if (!definitions.ContainsKey(type) || !definitions[type].ContainsKey(definitionName)) throw new ArgumentException("Could not find skin of type " + type.Name + " with name " + definitionName); + if (!definitions.ContainsKey(type) || !definitions[type].ContainsKey(definitionName)) throw new KeyNotFoundException("Could not find skin of type " + type.Name + " with name " + definitionName); return definitions[type][definitionName]; } @@ -66,8 +98,9 @@ namespace RecrownedAthenaeum.UI.Skin /// /// The type of definition the default should be coming from. /// The default definition for the given type. - public ISkinDefinitionData ObtainDefinition(Type type) + public virtual ISkinDefinitionData ObtainDefinition(Type type) { + if (disposed) throw new ObjectDisposedException(GetType().Name); return ObtainDefinition(null, type); } @@ -78,8 +111,9 @@ namespace RecrownedAthenaeum.UI.Skin /// The name of the definition. /// UIModule type the definition defines. /// The definition cast to T. - public T ObtainDefinition(string definitionName, Type type) where T : ISkinDefinitionData + public virtual T ObtainDefinition(string definitionName, Type type) where T : ISkinDefinitionData { + if (disposed) throw new ObjectDisposedException(GetType().Name); if (definitionName == null) definitionName = "default"; return (T)ObtainDefinition(definitionName, type); } @@ -90,8 +124,9 @@ namespace RecrownedAthenaeum.UI.Skin /// Convenience to cast to T. /// The type of the UIModule to retrieve the default from. /// The default definition for the given type. - public T ObtainDefinition(Type type) where T : ISkinDefinitionData + public virtual T ObtainDefinition(Type type) where T : ISkinDefinitionData { + if (disposed) throw new ObjectDisposedException(GetType().Name); return ObtainDefinition(null, type); } @@ -100,8 +135,10 @@ namespace RecrownedAthenaeum.UI.Skin /// /// The name of the definition. /// The definition itself. - public void AddDefinition(string definitionName, ISkinDefinitionData skinDefinition) + public virtual void AddDefinition(string definitionName, ISkinDefinitionData skinDefinition) { + if (disposed) throw new ObjectDisposedException(GetType().Name); + if (Laminated) throw new InvalidOperationException("This object has been laminated and cannot be edited."); if (!definitions.ContainsKey(skinDefinition.UIModuleType)) { definitions.Add(skinDefinition.UIModuleType, new Dictionary()); @@ -111,19 +148,55 @@ namespace RecrownedAthenaeum.UI.Skin } /// - /// Removes the definition. + /// Adds color to skin. /// - /// The name of the definition. - /// The type of the definition. - public void RemoveDefinition(string definitionName, Type definitionType) + /// + /// + public virtual void AddColor(string name, Color color) { - if (definitions.ContainsKey(definitionType) && definitions[definitionType].ContainsKey(definitionName)) + if (Laminated) throw new InvalidOperationException("This object has been laminated and cannot be edited."); + colors.Add(name, color); + } + + /// + /// Laminates the skin. Making sure no more additions are done and sets the skin to be ready for use. + /// Needs to be called before any use of skin. Building skin needs to be done before lamination. + /// + public void Laminate() + { + Laminated = true; + } + + /// + /// Disposes and the holding the cursor texture. + /// + public void Dispose() + { + if (disposed) throw new ObjectDisposedException(GetType().Name); + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Overridable dispose function. + /// + /// true when it's a user call to dispose. + public virtual void Dispose(bool disposing) + { + disposed = true; + if (disposing && !disposed) { - definitions[definitionType].Remove(definitionName); - } else - { - throw new ArgumentException("a definition of type " + definitionType.Name + " with a name of " + definitionName + " does not exist."); + textureAtlas.Dispose(); + CursorTexture.Dispose(); } } + + /// + /// Destructor. Calls the dispose with false. + /// + ~Skin() + { + Dispose(false); + } } } diff --git a/RecrownedAthenaeum/UI/Skin/SkinManager.cs b/RecrownedAthenaeum/UI/Skin/SkinManager.cs index 645eed2..74585f7 100644 --- a/RecrownedAthenaeum/UI/Skin/SkinManager.cs +++ b/RecrownedAthenaeum/UI/Skin/SkinManager.cs @@ -2,8 +2,9 @@ using Microsoft.Xna.Framework.Graphics; using Newtonsoft.Json; using RecrownedAthenaeum.Pipeline; -using RecrownedAthenaeum.Serializable; +using RecrownedAthenaeum.Data; using RecrownedAthenaeum.SpecialTypes; +using RecrownedAthenaeum.UI.Skin.Definitions; using System; using System.Collections.Generic; using System.IO; @@ -16,10 +17,29 @@ namespace RecrownedAthenaeum.UI.Skin public class SkinManager { private const string EXTENSION = ".rbskin"; + + private readonly MergedSkin mergedSkin = new MergedSkin(); + + /// + /// the skin that favors the selected skin, but still has a fallback to the default skin in case anything is missing. + /// + public ISkin Skin { get { return mergedSkin; } } + + /// + /// The user selected skin. + /// + public ISkin SelectedSkin { get { return mergedSkin.mainSkin; } set { mergedSkin.mainSkin = value; } } + + /// + /// The fallback skin in case the selected skin doesn't cover a specific definition or color. + /// + public ISkin BaseSkin { get { return mergedSkin.alternateSkin; } set { mergedSkin.alternateSkin = value; } } + /// /// The directory that contains the skins. /// public string skinsDirectory; + List skinPaths = new List(); /// @@ -49,27 +69,43 @@ namespace RecrownedAthenaeum.UI.Skin /// Generate skin from skin data. /// /// The skin data to generate skin from. - /// The path pointing the ".rbskin" file. + /// The path pointing to the file with the extension "". /// The graphics device to generate the texture. /// The skin generated from the skin data. public Skin GenerateSkinFromData(SkinData skinData, string path, GraphicsDevice graphicsDevice) { TextureAtlasDataReader textureAtlasDataReader = new TextureAtlasDataReader(); - DirectoryInfo parentFolder = Directory.GetParent(path); - TextureAtlasData atlasData = JsonConvert.DeserializeObject(parentFolder.FullName + "/" + skinData.nameOfTextureAtlas); + FileInfo[] skinFiles = Directory.GetParent(path).GetFiles(); + Dictionary fileNameWithPath = new Dictionary(); + for (int i = 0; i < skinFiles.Length; i++) + { + fileNameWithPath.Add(skinFiles[i].Name, skinFiles[i].FullName); + } + TextureAtlasData atlasData = JsonConvert.DeserializeObject(fileNameWithPath[skinData.nameOfTextureAtlas]); Texture2D atlasTexture; - using (FileStream stream = new FileStream(parentFolder.FullName + "/" + atlasData.textureName, FileMode.Open)) + using (FileStream stream = new FileStream(fileNameWithPath[atlasData.textureName], FileMode.Open)) { atlasTexture = Texture2D.FromStream(graphicsDevice, stream); } TextureAtlas.Region[] regions = textureAtlasDataReader.GenerateAtlasRegionsFromData(atlasData, atlasTexture); - - Skin skin = new Skin(new TextureAtlas(atlasTexture, regions)); + TextureAtlas textureAtlas = new TextureAtlas(atlasTexture, regions); + Texture2D cursorTexture; + if (Path.HasExtension(skinData.cursorTextureName) && fileNameWithPath.ContainsKey(skinData.cursorTextureName)) + { + using (FileStream stream = new FileStream(fileNameWithPath[skinData.cursorTextureName], FileMode.Open)) + { + cursorTexture = Texture2D.FromStream(graphicsDevice, stream); + } + } else + { + cursorTexture = textureAtlas[skinData.cursorTextureName].AsTexture2D(graphicsDevice); + } + Skin skin = new Skin(new TextureAtlas(atlasTexture, regions), cursorTexture); for (int i = 0; i < skinData.colors.Length; i++) { SkinData.ColorData colorData = skinData.colors[i]; - skin.colors.Add(colorData.name, new Color(colorData.r, colorData.g, colorData.b, colorData.a)); + skin.AddColor(colorData.name, new Color(colorData.r, colorData.g, colorData.b, colorData.a)); } for (int i = 0; i < skinData.definitions.Length; i++) @@ -100,5 +136,6 @@ namespace RecrownedAthenaeum.UI.Skin return skins; } + } } diff --git a/RecrownedAthenaeum/UI/Skin/SkinStack.cs b/RecrownedAthenaeum/UI/Skin/SkinStack.cs new file mode 100644 index 0000000..99cfd56 --- /dev/null +++ b/RecrownedAthenaeum/UI/Skin/SkinStack.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using RecrownedAthenaeum.SpecialTypes; +using RecrownedAthenaeum.UI.Skin.Definitions; + +namespace RecrownedAthenaeum.UI.Skin +{ + internal class MergedSkin : ISkin + { + /// + /// The skin to try to use first. + /// + public ISkin mainSkin; + + /// + /// The fallback skin. + /// + public ISkin alternateSkin; + + public Texture2D CursorTexture + { + get + { + if (mainSkin.CursorTexture != null) return mainSkin.CursorTexture; + return alternateSkin.CursorTexture; + } + } + + public void Draw(string regionName, string color, SpriteBatch batch, Rectangle destination, float rotation = 0, Vector2 origin = default(Vector2)) + { + try + { + mainSkin.Draw(regionName, color, batch, destination, rotation, origin); + } catch (KeyNotFoundException) + { + alternateSkin.Draw(regionName, color, batch, destination, rotation, origin); + } catch (NullReferenceException) + { + alternateSkin.Draw(regionName, color, batch, destination, rotation, origin); + } + } + + public Color GetColor(string name) + { + try + { + return mainSkin.GetColor(name); + } catch (KeyNotFoundException) + { + return alternateSkin.GetColor(name); + } + catch (NullReferenceException) + { + return alternateSkin.GetColor(name); + } + } + + public TextureAtlas.Region GetTextureAtlasRegion(string name) + { + try + { + return mainSkin.GetTextureAtlasRegion(name); + } catch (KeyNotFoundException) + { + return alternateSkin.GetTextureAtlasRegion(name); + } + catch (NullReferenceException) + { + return alternateSkin.GetTextureAtlasRegion(name); + } + } + + public ISkinDefinitionData ObtainDefinition(string definitionName, Type type) + { + try + { + return mainSkin.ObtainDefinition(definitionName, type); + } catch (KeyNotFoundException) + { + return alternateSkin.ObtainDefinition(definitionName, type); + } + catch (NullReferenceException) + { + return alternateSkin.ObtainDefinition(definitionName, type); + } + } + + public ISkinDefinitionData ObtainDefinition(Type type) + { + try + { + return mainSkin.ObtainDefinition(type); + } + catch (KeyNotFoundException) + { + return alternateSkin.ObtainDefinition(type); + } + catch (NullReferenceException) + { + return alternateSkin.ObtainDefinition(type); + } + } + + public T ObtainDefinition(string definitionName, Type type) where T : ISkinDefinitionData + { + try + { + return mainSkin.ObtainDefinition(definitionName, type); + } + catch (KeyNotFoundException) + { + return alternateSkin.ObtainDefinition(definitionName, type); + } + catch (NullReferenceException) + { + return alternateSkin.ObtainDefinition(definitionName, type); + } + } + + public T ObtainDefinition(Type type) where T : ISkinDefinitionData + { + try + { + return mainSkin.ObtainDefinition(type); + } + catch (KeyNotFoundException) + { + return alternateSkin.ObtainDefinition(type); + } + catch (NullReferenceException) + { + return alternateSkin.ObtainDefinition(type); + } + } + } +}