using Godot; using System.Collections.Generic; using System.IO; namespace Theriapolis.GodotHost.Platform; /// /// Loads PNGs from Content/Gfx as Godot ImageTextures and caches them by /// relative path. Texture filter is set to Nearest (project default for /// pixel art). /// /// This bypasses Godot's res:// import pipeline because Content/ lives /// outside the project — but for static pixel-art assets at native size /// the import pipeline doesn't add anything we need. /// /// Tactical-view tile rendering (M4) will hit this from chunk streamers, /// so the cache is per-process and never evicted; the full atlas /// (~50 PNGs at 32x32) is well under 1 MB. /// public static class ContentLoader { private static readonly Dictionary _cache = new(); /// /// Loads a PNG from Content/Gfx/<relativePath>. Returns /// null and logs an error if the file is missing or unreadable. /// public static ImageTexture? LoadGfx(string relativePath) { if (_cache.TryGetValue(relativePath, out var cached)) return cached; string absolute = Path.Combine(ContentPaths.GfxDir, relativePath); if (!File.Exists(absolute)) { // Silent miss — callers (e.g. atlas variant probes) treat null // as "no more variants" and shouldn't generate error noise. // Genuine missing-asset diagnostics live in AssetTest's summary. return null; } var image = Image.LoadFromFile(absolute); if (image is null) { GD.PrintErr($"[ContentLoader] Image.LoadFromFile failed: {absolute}"); return null; } var tex = ImageTexture.CreateFromImage(image); _cache[relativePath] = tex; return tex; } public static int CacheCount => _cache.Count; /// Drops every cached texture. Useful for hot-reload tests. public static void ClearCache() => _cache.Clear(); }