#nullable enable using System.IO; using Newtonsoft.Json; using T3.Core.Resource; using T3.Serialization; namespace T3.Editor.External; /// /// This is how we make HlslTools work with our shader linking /// ///
Todo: make generic for supporting other IDEs (jetbrains, vs, vim??) ///
internal static class ShaderLinter { public static void AddPackage(IResourcePackage package, IEnumerable? additionalPackages, bool replaceExisting = false) { // package.ResourcesFolder now points to ".../Assets" var filePath = Path.Combine(package.AssetsFolder, FileName); var jsonObject = new HlslToolsJson(filePath); var resourceFolderList = jsonObject.IncludeDirectories; var virtualIncludeDirectories = jsonObject.VirtualDirectoryMappings; resourceFolderList.Add(package.AssetsFolder); if (package.Name != null) { // Maps "/ProjectName" to ".../ProjectName/Assets/Shaders" virtualIncludeDirectories.Add('/' + package.Name, package.AssetsFolder + "/shaders/"); } if (additionalPackages is not null) { foreach (var p in additionalPackages) { resourceFolderList.Add(p.AssetsFolder + "/shaders/"); if (p.Name != null) { virtualIncludeDirectories.TryAdd('/' + p.Name, p.AssetsFolder + "/shaders/"); } } } if (!package.IsReadOnly) { if (!JsonUtils.TrySaveJson(jsonObject, filePath)) { Log.Error($"{nameof(ShaderLinter)}: failed to save {FileName} to \"{filePath}\""); return; } } if (!replaceExisting) { _hlslToolsJsons.Add(package, jsonObject); } else { var existing = _hlslToolsJsons.SingleOrDefault(x => x.Key.AssetsFolder == package.AssetsFolder); if (existing.Key != null) { _hlslToolsJsons.Remove(existing.Key); } } } private static void TryDelete(string filePath) { try { File.Delete(filePath); } catch (Exception e) { Log.Error($"{nameof(ShaderLinter)}: failed to delete {filePath}: {e.Message}"); } } [Serializable] private class HlslToolsJson(string filePath) { [JsonProperty("root")] public readonly bool Root = true; [JsonProperty("hlsl.preprocessorDefinitions")] public readonly string[] PreProcessorDefinitions = Array.Empty(); [JsonProperty("hlsl.additionalIncludeDirectories")] public readonly List IncludeDirectories = ["."]; [JsonProperty("hlsl.virtualDirectoryMappings")] public readonly Dictionary VirtualDirectoryMappings = new(); [JsonIgnore] public string FilePath = filePath; } public static void RemovePackage(IResourcePackage resourcePackage) { if (!_hlslToolsJsons.TryGetValue(resourcePackage, out var json)) { Log.Error($"{nameof(ShaderLinter)}: failed to remove {resourcePackage.AssetsFolder}"); return; } var filePath = json.FilePath; TryDelete(filePath); _hlslToolsJsons.Remove(resourcePackage); if (Program.IsShuttingDown) return; var resourceFolder = resourcePackage.AssetsFolder; foreach (var dependent in _hlslToolsJsons.Values) { if (dependent.IncludeDirectories.Remove(resourceFolder)) JsonUtils.TrySaveJson(json, dependent.FilePath); } } private static readonly Dictionary _hlslToolsJsons = new(); private const string FileName = "shadertoolsconfig.json"; }