Files
RobustToolbox/ClientResourceManager/ResourceManager.cs
T

335 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Windows.Forms;
using GorgonLibrary;
using GorgonLibrary.Graphics;
using GorgonLibrary.InputDevices;
using GorgonLibrary.FileSystems;
using GorgonLibrary.Framework;
using GorgonLibrary.GUI;
using GorgonLibrary.Graphics.Utilities;
using System.Globalization;
using System.Text.RegularExpressions;
using ClientConfigManager;
namespace ClientResourceManager
{
public struct SpriteInfo
{
public string name;
public Vector2D Offsets;
public Vector2D Size;
}
/// <summary>
/// This class manages Resource loading, caching and distribution.
/// </summary>
public class ResMgr
{
private FileSystem FileSystem;
private FileSystem GuiFileSystem;
private Dictionary<string, Image> Images = new Dictionary<string, Image>();
private Dictionary<string, FXShader> Shaders = new Dictionary<string, FXShader>();
private Dictionary<string, SpriteInfo> SpriteInfos = new Dictionary<string, SpriteInfo>();
private Dictionary<string, Sprite> Sprites = new Dictionary<string, Sprite>();
private Dictionary<string, GUISkin> GuiSkins = new Dictionary<string, GUISkin>();
private Dictionary<string, System.Drawing.Rectangle> GuiInfo = new Dictionary<string, System.Drawing.Rectangle>();
private Dictionary<string, Font> Fonts = new Dictionary<string, Font>();
private static ResMgr singleton;
private ResMgr() { }
public static ResMgr Singleton
{
get
{
if (singleton == null)
{
singleton = new ResMgr();
}
return singleton;
}
}
/// <summary>
/// Retrieves the GUI Skin with the given key from the Resource list. Returns null if not found.
/// </summary>
public GUISkin GetGuiSkin(string key)
{
if (GuiSkins.ContainsKey(key)) return GuiSkins[key];
else return null;
}
/// <summary>
/// Retrieves information describing a sprite from a GUI Skin. Returns an empty rectangle if not found.
/// </summary>
public System.Drawing.Rectangle GetGUIInfo(string key)
{
if (GuiInfo.ContainsKey(key)) return GuiInfo[key];
else return System.Drawing.Rectangle.Empty;
}
/// <summary>
/// <para>Retrieves the Image with the given key from the Resource list and returns it as a Sprite.</para>
/// <para>If a sprite has been created before using this method, it will return that Sprite. Returns error Sprite if not found.</para>
/// </summary>
public Sprite GetSpriteFromImage(string key)
{
if (Images.ContainsKey(key))
{
if (Sprites.ContainsKey(key))
{
return Sprites[key];
}
else
{
Sprite newSprite = new Sprite(key, Images[key]);
Sprites.Add(key, newSprite);
return newSprite;
}
}
else return new Sprite(key + "Missing", Images["noSprite"]);
}
/// <summary>
/// Retrieves the Sprite with the given key from the Resource list. Returns error Sprite if not found.
/// </summary>
public Sprite GetSprite(string key)
{
if (Sprites.ContainsKey(key)) return Sprites[key];
else return GetSpriteFromImage(key);
}
/// <summary>
/// Checks if a sprite with the given key is in the resource list
/// </summary>
/// <param name="key">key to check</param>
/// <returns></returns>
public bool SpriteExists(string key)
{
return Sprites.ContainsKey(key);
}
/// <summary>
/// Retrieves the SpriteInfo with the given key from the Resource list. Returns null if not found.
/// </summary>
public SpriteInfo? GetSpriteInfo(string key)
{
if (SpriteInfos.ContainsKey(key)) return SpriteInfos[key];
else return null;
}
/// <summary>
/// Retrieves the Shader with the given key from the Resource list. Returns null if not found.
/// </summary>
public FXShader GetShader(string key)
{
if (Shaders.ContainsKey(key)) return Shaders[key];
else return null;
}
/// <summary>
/// Retrieves the Image with the given key from the Resource list. Returns error Image if not found.
/// </summary>
public Image GetImage(string key)
{
if (Images.ContainsKey(key)) return Images[key];
else return Images["noSprite"];
}
/// <summary>
/// Retrieves the Font with the given key from the Resource list. Returns null if not found.
/// </summary>
public Font GetFont(string key)
{
if (Fonts.ContainsKey(key)) return Fonts[key];
else return null;
}
/// <summary>
/// Initializes the Resource Manager and caches all resources.
/// </summary>
public void Initialize()
{
FileSystemProvider.Load(@".\GorgonBZip2FileSystem.dll");
FileSystem = FileSystem.Create("ResourceFS", FileSystemProviderCache.Providers["Gorgon.BZip2FileSystem"]);
GuiFileSystem = FileSystem.Create("GuiFS", FileSystemProviderCache.Providers["Gorgon.BZip2FileSystem"]);
if (!File.Exists(ConfigManager.Singleton.Configuration.ResourcePack)) throw new FileNotFoundException("Resource Pack not found : " + ConfigManager.Singleton.Configuration.ResourcePack);
FileSystem.AssignRoot(ConfigManager.Singleton.Configuration.ResourcePack);
LoadFiles();
LoadGUIs();
}
private void LoadGUIs()
{
if (!Directory.Exists(ConfigManager.Singleton.Configuration.GuiFolder)) throw new FileNotFoundException("GUI Folder missing : " + ConfigManager.Singleton.Configuration.GuiFolder);
string[] guiFiles = Directory.GetFiles(ConfigManager.Singleton.Configuration.GuiFolder, "*.gui", SearchOption.TopDirectoryOnly);
foreach (string currentGuiFile in guiFiles)
{
string guiName = Path.GetFileNameWithoutExtension(currentGuiFile);
if (GuiSkins.ContainsKey(guiName)) continue; //Already exists. This shouldnt even be possible. Would require 2+ Files with the same name in the same dir.
GuiFileSystem.AssignRoot(currentGuiFile); //Or someone loading this twice...
GUISkin newSkin = GUISkin.FromFile(GuiFileSystem);
GuiSkins.Add(guiName, newSkin);
}
foreach (GUISkin skin in GuiSkins.Values)
{
foreach (GUIElement element in skin.Elements)
{
if (!GuiInfo.ContainsKey(element.Name))
{
GuiInfo.Add(element.Name,
new System.Drawing.Rectangle(element.Dimensions.X, element.Dimensions.Y,
element.Dimensions.Width, element.Dimensions.Height));
}
}
}
}
private void LoadFiles()
{
var ImageQuery = from FileSystemFile file in FileSystem where file.Extension.ToLower() == ".png" select file;
foreach (FileSystemFile file in ImageQuery)
{
Image loadedImg;
if (ImageCache.Images.Contains(file.Filename))
loadedImg = ImageCache.Images[file.Filename];
else
loadedImg = Image.FromFileSystem(FileSystem, file.FullPath);
if (!Images.ContainsKey(file.Filename)) Images.Add(file.Filename, loadedImg);
}
var FontQuery = from FileSystemFile file in FileSystem where file.Extension.ToLower() == ".ttf" select file;
foreach (FileSystemFile file in FontQuery)
{
Font loadedFont;
if (FontCache.Fonts.Contains(file.Filename))
loadedFont = FontCache.Fonts[file.Filename];
else
loadedFont = Font.FromFileSystem(FileSystem, file.FullPath, 10);
if (!Fonts.ContainsKey(file.Filename))
Fonts.Add(file.Filename, loadedFont);
}
#region TAI Loading / Parsing
//Structure of a TAI file line for reference.
//<filename>\t\t<atlas filename>, <atlas index>, <atlas type>, <x offset>, <y offset>, <depth offset>, <width>, <height>
// 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7
var TAIQuery = from FileSystemFile file in FileSystem where file.Extension.ToLower() == ".tai" select file;
foreach (FileSystemFile file in TAIQuery)
{
string taiContents = Encoding.UTF8.GetString(FileSystem.ReadFile(file.FullPath));
string[] splitContents = Regex.Split(taiContents, "\r\n"); //Split by newlines.
foreach (string line in splitContents)
{
if (String.IsNullOrWhiteSpace(line)) continue; //There seems to be an empty line at the end of these files.
string[] splitLine = line.Split(','); //Split line by commas.
string[] fullPath = Regex.Split(splitLine[0], "\t");
//Split first part by tabs - its the original filepath & filename , two tabs and then the name of the atlas texture.
//So we end up with fullPath[0] being the original path and fullPath[2] being the name of the atlas texture. fullPath[1] is an empty string between the 2 tabs.
string originalName = Path.GetFileNameWithoutExtension(fullPath[0]);
//The name of the original picture without extension, before it became part of the atlas.
//This will be the name we can find this under in our Resource lists.
string[] splitResourceName = fullPath[2].Split('.');
if (!ImageCache.Images.Contains(splitResourceName[0]))
{
//Image for this sprite does not exist. Possibly set to defered later.
continue;
}
Image atlasTex = ImageCache.Images[splitResourceName[0]]; //Grab the image for the sprite from the cache.
SpriteInfo info = new SpriteInfo();
info.name = originalName;
float offsetX = 0;
float offsetY = 0;
float sizeX = 0;
float sizeY = 0;
if (splitLine.Length > 8) //Separated with , - This causes some problems. Happens on some systems.
{
offsetX = float.Parse(splitLine[3] + "." + splitLine[4], CultureInfo.InvariantCulture);
offsetY = float.Parse(splitLine[5] + "." + splitLine[6], CultureInfo.InvariantCulture);
sizeX = float.Parse(splitLine[8] + "." + splitLine[9], CultureInfo.InvariantCulture);
sizeY = float.Parse(splitLine[10] + "." + splitLine[11], CultureInfo.InvariantCulture);
}
else //Seperated with SOMETHING ELSE. This is good.
{
offsetX = float.Parse(splitLine[3], CultureInfo.InvariantCulture);
offsetY = float.Parse(splitLine[4], CultureInfo.InvariantCulture);
sizeX = float.Parse(splitLine[6], CultureInfo.InvariantCulture);
sizeY = float.Parse(splitLine[7], CultureInfo.InvariantCulture);
}
info.Offsets = new Vector2D((float)Math.Round(offsetX * (float)atlasTex.Width,1), (float)Math.Round(offsetY * (float)atlasTex.Height,1));
info.Size = new Vector2D((float)Math.Round(sizeX * (float)atlasTex.Width,1), (float)Math.Round(sizeY * (float)atlasTex.Height,1));
Sprite newSprite = new Sprite(originalName, atlasTex, info.Offsets, info.Size);
if (!Sprites.ContainsKey(originalName)) Sprites.Add(originalName, newSprite);
if (!SpriteInfos.ContainsKey(originalName)) SpriteInfos.Add(originalName, info);
}
}
#endregion
var ShaderQuery = from FileSystemFile file in FileSystem where file.Extension.ToLower() == ".fx" select file;
foreach (FileSystemFile file in ShaderQuery)
{
try
{
FXShader loadedShader;
if (ShaderCache.Shaders.Contains(file.Filename))
continue;
else
loadedShader = FXShader.FromFileSystem(FileSystem, file.FullPath, ShaderCompileOptions.None);
if (!Shaders.ContainsKey(file.Filename)) Shaders.Add(file.Filename, loadedShader);
}
catch (Exception EX)
{
MessageBox.Show(EX.Message,file.Filename);
}
}
}
}
}