using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Linq; using Godot; namespace KeepersCompound.TMV; public partial class TextureLoader { private readonly string _userTexturesPath; private readonly string _rootFamPath; // TODO: Load from installation resources private readonly string _fmPath; private readonly Dictionary _rootTexturePaths = new(); private readonly Dictionary _fmTexturePaths = new(); private readonly List _textureCache = new(); private readonly Dictionary _idMap = new(); private readonly Dictionary _pathMap = new(); public TextureLoader(string rootFamPath, string fmPath) { _rootFamPath = rootFamPath; _fmPath = fmPath; _userTexturesPath = ProjectSettings.GlobalizePath($"user://textures/tmp"); ExtractRootFamFiles(); LoadDefaultTexture(); RegisterTexturePaths(_fmPath, _fmTexturePaths); RegisterTexturePaths(_userTexturesPath, _rootTexturePaths); } private void ExtractRootFamFiles() { var dir = new DirectoryInfo(_userTexturesPath); if (dir.Exists) { dir.Delete(true); } var zip = ZipFile.OpenRead(_rootFamPath); zip.ExtractToDirectory(_userTexturesPath.PathJoin("fam")); } private void LoadDefaultTexture() { // TODO: This should be a resource loaded from RES const string path = "user://textures/jorge.png"; var texture = ImageTexture.CreateFromImage(Image.LoadFromFile(path)); _textureCache.Add(texture); } private static void RegisterTexturePaths(string rootDir, Dictionary map) { // TODO: Load DDS BMP GIF CEL string[] validExtensions = { "png", "tga", "pcx" }; var famOptions = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive }; var textureOptions = new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = true, }; foreach (var dirPath in Directory.EnumerateDirectories(rootDir, "fam", famOptions)) { foreach (var path in Directory.EnumerateFiles(dirPath, "*", textureOptions)) { if (validExtensions.Contains(path.GetExtension().ToLower())) { // TODO: This only adds the first one found rather than the highest priority var key = path.TrimPrefix(rootDir).GetBaseName().ToLower(); map.TryAdd(key, path); } } } GD.Print($"Registered {map.Count} texture paths at : {rootDir}"); } public bool Load(int id, string path) { var loaded = false; if (_fmTexturePaths.TryGetValue(path.ToLower(), out var fmTexPath)) { _textureCache.Add(LoadTexture(fmTexPath)); loaded = true; } else if (_rootTexturePaths.TryGetValue(path.ToLower(), out var rootTexPath)) { _textureCache.Add(LoadTexture(rootTexPath)); loaded = true; } var index = loaded ? _textureCache.Count - 1 : 0; _idMap.TryAdd(id, index); _pathMap.TryAdd(path, index); return loaded; } public static ImageTexture LoadTexture(string path) { var ext = path.GetExtension().ToLower(); var texture = ext switch { "pcx" => LoadPcx(path), "gif" => LoadGif(path), _ => ImageTexture.CreateFromImage(Image.LoadFromFile(path)), }; return texture; } public ImageTexture Get(int id) { if (!_idMap.ContainsKey(id)) { return _textureCache[0]; } return _textureCache[_idMap[id]]; } public ImageTexture Get(string path) { if (!_pathMap.ContainsKey(path)) { return _textureCache[0]; } return _textureCache[_pathMap[path]]; } }