diff --git a/GlitchyEditor/src/AssetFile.bf b/GlitchyEditor/src/AssetFile.bf index 1f5cb7c..ea4f293 100644 --- a/GlitchyEditor/src/AssetFile.bf +++ b/GlitchyEditor/src/AssetFile.bf @@ -140,16 +140,18 @@ class AssetFile GenerateAssetHandle(); - var assetPipeline = _contentManager.GetDefaultProcessors(fileExtension); + IAssetImporter assetImporter = _contentManager.GetAssetImporter(fileExtension); + IAssetProcessor assetProcessor = ?; //_contentManager.GetAssetProcessor(assetImporter.); + IAssetExporter assetExporter = ?; //_contentManager.GetAssetProcessor(assetImporter.); // TODO! //if (assetPipeline case .Err) // return; var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension); - + // We don't have a loader -> we don't need a config - if (assetLoader == null && assetPipeline case .Err) + if (assetLoader == null && assetImporter == null) return; if (assetLoader != null) @@ -162,16 +164,16 @@ class AssetFile } _assetConfig.Importer = new String(); - assetPipeline?.Importer?.GetType()?.GetName(_assetConfig.Importer); - _assetConfig.ImporterConfig = assetPipeline?.Importer.CreateDefaultConfig(); + assetImporter?.GetType()?.GetName(_assetConfig.Importer); + _assetConfig.ImporterConfig = assetImporter?.CreateDefaultConfig(); _assetConfig.Processor = new String(); - assetPipeline?.Processor?.GetType()?.GetName(_assetConfig.Processor); - _assetConfig.ProcessorConfig = assetPipeline?.Processor.CreateDefaultConfig(); + assetProcessor?.GetType()?.GetName(_assetConfig.Processor); + _assetConfig.ProcessorConfig = assetProcessor.CreateDefaultConfig(); _assetConfig.Exporter = new String(); - assetPipeline?.Exporter?.GetType()?.GetName(_assetConfig.Exporter); - _assetConfig.ExporterConfig = assetPipeline?.Exporter.CreateDefaultConfig(); + assetExporter?.GetType()?.GetName(_assetConfig.Exporter); + _assetConfig.ExporterConfig = assetExporter.CreateDefaultConfig(); SaveAssetConfig(); } diff --git a/GlitchyEditor/src/Assets/AssetConverter.bf b/GlitchyEditor/src/Assets/AssetConverter.bf index f52a22d..86a441f 100644 --- a/GlitchyEditor/src/Assets/AssetConverter.bf +++ b/GlitchyEditor/src/Assets/AssetConverter.bf @@ -5,6 +5,8 @@ using System; using System.IO; using GlitchyEngine.Content; using GlitchyEditor.Assets.Processors; +using System.Threading; +using System.Threading.Tasks; namespace GlitchyEditor.Assets; @@ -14,6 +16,8 @@ class AssetConverter private EditorContentManager _contentManager; + private Dictionary _processingAssets ~ delete _; + public this(EditorContentManager contentManager) { _contentManager = contentManager; @@ -21,10 +25,10 @@ class AssetConverter public void QueueForProcessing(AssetFile assetFile, bool isBlocking = false) { - if (!isBlocking) - _queue.Add(assetFile); - else + if (isBlocking) Process(assetFile); + else + _queue.Add(assetFile); } public void Update() @@ -44,7 +48,6 @@ class AssetConverter { IAssetImporter importer = _contentManager.GetAssetImporter(assetFile); IAssetProcessor processor = _contentManager.GetAssetProcessor(assetFile); - IAssetExporter exporter = _contentManager.GetAssetExporter(assetFile); if (importer == null) { @@ -57,12 +60,6 @@ class AssetConverter Log.EngineLogger.Error("Processor is null!"); return; } - - if (exporter == null) - { - Log.EngineLogger.Error("Exporter is null!"); - return; - } Result importResult = importer.Import(assetFile.AssetFile.Path, assetFile.AssetFile.Identifier, assetFile.AssetConfig.ImporterConfig); @@ -75,7 +72,10 @@ class AssetConverter defer { delete importResult.Value; } - Result processResult = processor.Process(importResult.Value, assetFile.AssetConfig.ProcessorConfig); + List resources = scope .(); + defer { ClearAndDeleteItems!(resources); } + + Result processResult = processor.Process(importResult.Value, assetFile.AssetConfig.ProcessorConfig, resources); if (processResult case .Err) { @@ -83,16 +83,30 @@ class AssetConverter return; } - defer { delete processResult.Value; } + for (ProcessedResource resource in resources) + { + TrySilent!(ExportResource(assetFile, resource)); + } + } + + private Result ExportResource(AssetFile assetFile, ProcessedResource resource) + { + IAssetExporter exporter = _contentManager.GetAssetExporter(resource.AssetType); + + if (exporter == null) + { + Log.EngineLogger.Error($"No exporter for asset type {resource.AssetType}!"); + return .Err; + } MemoryStream memoryStream = scope .(); - Result exportResult = exporter.Export(memoryStream, processResult.Value, assetFile.AssetConfig.ExporterConfig); + Result exportResult = exporter.Export(memoryStream, resource, assetFile.AssetConfig.ExporterConfig); if (exportResult case .Err) { Log.EngineLogger.Error("Failed to export asset!"); - return; + return .Err; } CachedAsset assetInfo = scope CachedAsset(); @@ -100,11 +114,14 @@ class AssetConverter assetInfo.CreationTimestamp = DateTime.UtcNow; assetInfo.Compression = assetFile.AssetConfig.ExporterConfig.Compression; assetInfo.AssetIdentifier = new AssetIdentifier(assetFile.AssetFile.Identifier); - assetInfo.AssetType = processResult.Value.AssetType; + assetInfo.AssetType = resource.AssetType; if (_contentManager.AssetCache.SaveAsset(assetInfo, memoryStream.Memory) case .Err) { Log.EngineLogger.Error("Failed to write asset to cache."); + return .Err; } + + return .Ok; } } \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/AssetNode.bf b/GlitchyEditor/src/Assets/AssetNode.bf index 9db6884..25cc9f5 100644 --- a/GlitchyEditor/src/Assets/AssetNode.bf +++ b/GlitchyEditor/src/Assets/AssetNode.bf @@ -27,7 +27,7 @@ public class SubAsset { public AssetNode Asset; public String Name ~ delete _; - //public String AssetInternalPath ~ delete _; + public AssetIdentifier Identifier ~ delete _; public Texture2D PreviewImage ~ _?.ReleaseRef(); } diff --git a/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf b/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf index d9cf8ce..b888c56 100644 --- a/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf +++ b/GlitchyEditor/src/Assets/Exporters/TextureExporter.bf @@ -4,11 +4,14 @@ using GlitchyEngine.Renderer; using GlitchyEditor.Assets.Processors; using GlitchyEngine; using GlitchyEditor.Assets.Importers; +using GlitchyEngine.Content; namespace GlitchyEditor.Assets.Exporters; class TextureExporter : IAssetExporter { + public static AssetType ExportedAssetType => .Texture; + public AssetExporterConfig CreateDefaultConfig() { return new AssetExporterConfig(); diff --git a/GlitchyEditor/src/Assets/Importers/Config.bf b/GlitchyEditor/src/Assets/Importers/Config.bf index 86bdad1..70ce495 100644 --- a/GlitchyEditor/src/Assets/Importers/Config.bf +++ b/GlitchyEditor/src/Assets/Importers/Config.bf @@ -23,13 +23,13 @@ abstract class Config return true; } - public abstract void ShowEditor(); + public abstract void ShowEditor(AssetFile assetFile); } [BonTarget, BonPolyRegister] class AssetImporterConfig : Config { - public override void ShowEditor() + public override void ShowEditor(AssetFile assetFile) { } @@ -38,7 +38,7 @@ class AssetImporterConfig : Config [BonTarget, BonPolyRegister] class AssetProcessorConfig : Config { - public override void ShowEditor() + public override void ShowEditor(AssetFile assetFile) { } @@ -56,7 +56,7 @@ class AssetExporterConfig : Config set => SetIfChanged(ref _compression, value); } - public override void ShowEditor() + public override void ShowEditor(AssetFile assetFile) { ImGui.PropertyTableStartNewProperty("Compression"); ImGui.AttachTooltip("Specifies the compression method used to compress the processed asset."); diff --git a/GlitchyEditor/src/Assets/Importers/Interfaces.bf b/GlitchyEditor/src/Assets/Importers/Interfaces.bf index 117f126..add3bc6 100644 --- a/GlitchyEditor/src/Assets/Importers/Interfaces.bf +++ b/GlitchyEditor/src/Assets/Importers/Interfaces.bf @@ -12,19 +12,28 @@ interface IAssetImporter AssetImporterConfig CreateDefaultConfig(); + /// The type that ImportedResource returns. + static Type ProcessedAssetType { get; } + Result Import(StringView fullFileName, AssetIdentifier assetIdentifier, AssetImporterConfig config); } interface IAssetProcessor { AssetProcessorConfig CreateDefaultConfig(); + + /// The asset type that this processor can process. + static Type ProcessedAssetType { get; } - Result Process(ImportedResource importedResource, AssetProcessorConfig config); + Result Process(ImportedResource importedResource, AssetProcessorConfig config, List outProcessedResources); } interface IAssetExporter { AssetExporterConfig CreateDefaultConfig(); + /// The asset type that this exporter can export. + static AssetType ExportedAssetType { get; } + Result Export(Stream stream, ProcessedResource processedObject, AssetExporterConfig config); } diff --git a/GlitchyEditor/src/Assets/Importers/TextureImporter.bf b/GlitchyEditor/src/Assets/Importers/TextureImporter.bf index 0d38fd4..112b133 100644 --- a/GlitchyEditor/src/Assets/Importers/TextureImporter.bf +++ b/GlitchyEditor/src/Assets/Importers/TextureImporter.bf @@ -40,7 +40,7 @@ class TextureImporterConfig : AssetImporterConfig set => SetIfChanged(ref _isSrgb, value); } - public override void ShowEditor() + public override void ShowEditor(AssetFile assetFile) { ImGui.PropertyTableStartNewProperty("Is sRGB"); ImGui.AttachTooltip("If checked, the texture will be forced to be imported as sRGB. Refer to the documentation for an detailed explanation what you should do here."); diff --git a/GlitchyEditor/src/Assets/Processors/TextureProcessor.bf b/GlitchyEditor/src/Assets/Processors/TextureProcessor.bf index 9eb3ddf..7a0f0d3 100644 --- a/GlitchyEditor/src/Assets/Processors/TextureProcessor.bf +++ b/GlitchyEditor/src/Assets/Processors/TextureProcessor.bf @@ -5,6 +5,8 @@ using GlitchyEngine.Renderer; using GlitchyEngine.Content; using GlitchyEngine; using ImGui; +using System.Collections; +using GlitchyEngine.Math; namespace GlitchyEditor.Assets.Processors; @@ -16,14 +18,27 @@ enum GenerateMipMaps Kaiser } +enum TextureType +{ + Texture, + Sprite +} + + [BonTarget, BonPolyRegister] class TextureProcessorConfig : AssetProcessorConfig { [BonInclude] - private GenerateMipMaps _generateMipMaps; + private GenerateMipMaps _generateMipMaps = .No; [BonInclude] private SamplerStateDescription _samplerStateDescription = .(); + + [BonInclude] + private TextureType _textureType = .Texture; + + [BonInclude] + private List _sprites = new .() ~ DeleteContainerAndItems!(_); public GenerateMipMaps GenerateMipMaps { @@ -36,9 +51,64 @@ class TextureProcessorConfig : AssetProcessorConfig get => _samplerStateDescription; set => SetIfChanged(ref _samplerStateDescription, value); } - - public override void ShowEditor() + + public TextureType TextureType { + get => _textureType; + set => SetIfChanged(ref _textureType, value); + } + + public List Sprites => _sprites; + + public override void ShowEditor(AssetFile assetFile) + { + if (ImGui.BeginPopupModal("Apply Changes", null, .AlwaysAutoResize)) + { + ImGui.Text("The changes have to be applied before you can open the sprite editor.\nDo you want to apply the changes and continue?"); + + if (ImGui.Button("Apply")) + { + assetFile.SaveAssetConfig(); + ImGui.CloseCurrentPopup(); + + new SpriteEditor(Editor.Instance, assetFile.AssetConfig.AssetHandle); + } + + ImGui.SameLine(); + + if (ImGui.Button("Cancel")) + { + ImGui.CloseCurrentPopup(); + } + + ImGui.EndPopup(); + } + + ImGui.PropertyTableStartNewProperty("Texture Type"); + + TextureType textureType = _textureType; + if (ImGui.EnumCombo("##textureType", ref textureType)) + { + TextureType = textureType; + } + + ImGui.PropertyTableStartNewRow(); + + if (textureType == .Sprite) + { + if (ImGui.Button("Open Sprite Editor...")) + { + if (_changed) + { + ImGui.OpenPopup("Apply Changes"); + } + else + { + new SpriteEditor(Editor.Instance, assetFile.AssetConfig.AssetHandle); + } + } + } + ImGui.PropertyTableStartNewProperty("Generate Mip Maps", "Specifies the algorithm used to generate mip maps for this texture."); ImGui.BeginDisabled(); @@ -157,6 +227,14 @@ class TextureProcessorConfig : AssetProcessorConfig } } +public class SpriteDesc +{ + public String Name ~ delete _; + public int2 TopLeft; + public int2 Size; + public AssetHandle AssetHandle; +} + class ProcessedTexture : ProcessedResource { public Format PixelFormat = .Unknown; @@ -276,22 +354,46 @@ class ProcessedTexture : ProcessedResource } } +class ProcessedSprite : ProcessedResource +{ + public override AssetType AssetType => .Sprite; + + private AssetHandle _texture; + + private int2 _topLeft; + private int2 _size; + + public AssetHandle Texture => _texture; + + public int2 TopLeft => _topLeft; + public int2 Size => _size; + + public this(AssetIdentifier ownAssetIdentifier, AssetHandle texture, int2 topLeft, int2 size) : base(ownAssetIdentifier) + { + _texture = texture; + _topLeft = topLeft; + _size = size; + } +} + class TextureProcessor : IAssetProcessor { + public static Type ProcessedAssetType => typeof(ImportedTexture); + public AssetProcessorConfig CreateDefaultConfig() { return new TextureProcessorConfig(); } - public Result Process(ImportedResource importedObject, AssetProcessorConfig config) + public Result Process(ImportedResource importedObject, AssetProcessorConfig config, List outProcessedResources) { Log.EngineLogger.AssertDebug(config is TextureProcessorConfig); Log.EngineLogger.AssertDebug(importedObject is ImportedTexture); - return Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig)); + return Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig, outProcessedResources)); } - private Result ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config) + private Result ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config, List outProcessedResources) { ProcessedTexture processedTexture = new ProcessedTexture(new AssetIdentifier(importedTexture.AssetIdentifier.FullIdentifier)); @@ -322,8 +424,31 @@ class TextureProcessor : IAssetProcessor } // TODO: Pack to BC-Format or what ever was selected. + if (config.TextureType == .Sprite) + { + } - return processedTexture; + return .Ok; + } + + private void CreateSprites(ProcessedTexture processedTexture, TextureProcessorConfig config, List outProcessedResources) + { + if (processedTexture.Dimension != .Texture2D) + { + Log.ClientLogger.Error("Only 2D textures can be used as sprites."); + return; + } + + if (config.Sprites.Count == 0) + { + /*ProcessedSprite sprite = new ProcessedSprite(processedTexture.); + + processedTexture.Sprites.Add(new SpriteDesc(){ + Name = new String("Sprite"), + TopLeft = .(0, 0), + Size = .((.)processedTexture.Width, (.)processedTexture.Height) + });*/ + } } private int CalculateMipMapCount(int width, int height, int depth) diff --git a/GlitchyEditor/src/Assets/SpriteEditor.bf b/GlitchyEditor/src/Assets/SpriteEditor.bf new file mode 100644 index 0000000..cd5d7ac --- /dev/null +++ b/GlitchyEditor/src/Assets/SpriteEditor.bf @@ -0,0 +1,21 @@ +using System; +using GlitchyEditor.EditWindows; +using GlitchyEngine.Content; +using ImGui; + +namespace GlitchyEditor.Assets; + +class SpriteEditor : ClosableWindow +{ + AssetHandle _assetHandle; + + public this(Editor editor, AssetHandle assetHandle) : base(editor, "Sprite Editor") + { + _assetHandle = assetHandle; + } + + protected override void InternalShow() + { + ImGui.Text("Nothing to see here, yet..."); + } +} \ No newline at end of file diff --git a/GlitchyEditor/src/EditWindows/InspectorWindow.bf b/GlitchyEditor/src/EditWindows/InspectorWindow.bf index aa3b677..45c372b 100644 --- a/GlitchyEditor/src/EditWindows/InspectorWindow.bf +++ b/GlitchyEditor/src/EditWindows/InspectorWindow.bf @@ -137,9 +137,9 @@ class InspectorWindow : EditorWindow if (ImGui.BeginPropertyTable("asset_properties", ImGui.GetID("asset_properties"))) { - assetFile.AssetConfig?.ImporterConfig?.ShowEditor(); - assetFile.AssetConfig?.ProcessorConfig?.ShowEditor(); - assetFile.AssetConfig?.ExporterConfig?.ShowEditor(); + assetFile.AssetConfig?.ImporterConfig?.ShowEditor(assetFile); + assetFile.AssetConfig?.ProcessorConfig?.ShowEditor(assetFile); + assetFile.AssetConfig?.ExporterConfig?.ShowEditor(assetFile); ImGui.EndTable(); diff --git a/GlitchyEditor/src/EditorContentManager.bf b/GlitchyEditor/src/EditorContentManager.bf index e405c34..784386f 100644 --- a/GlitchyEditor/src/EditorContentManager.bf +++ b/GlitchyEditor/src/EditorContentManager.bf @@ -219,10 +219,14 @@ class EditorContentManager : IContentManager }; private append List _assetImporters = .() ~ ClearAndDeleteItems!(_); + private append Dictionary _extensionToAssetImporter = .(); private append List _assetProcessors = .() ~ ClearAndDeleteItems!(_); - private append List _assetExporters = .() ~ ClearAndDeleteItems!(_); + private append Dictionary _importedResourceToAssetProcessor = .(); + //private append List _assetExporters = .() ~ ClearAndDeleteItems!(_); private append Dictionary _defaultAssetProcessors = .() ~ delete:append _; + private append Dictionary _assetExporters = .() ~ ClearDictionaryAndDeleteValues!(_); + public void RegisterAssetLoader() where T : new, class, IAssetLoader { // Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered."); @@ -242,7 +246,11 @@ class EditorContentManager : IContentManager _assetImporters.Add(assetImporter); for (StringView ext in T.FileExtensions) - _supportedExtensions.Add(new String(ext)); + { + String fileExtension = new String(ext); + _supportedExtensions.Add(fileExtension); + _extensionToAssetImporter.Add(fileExtension, assetImporter); + } } public void RegisterAssetProcessor() where T : new, class, IAssetProcessor @@ -256,7 +264,29 @@ class EditorContentManager : IContentManager { T assetExporter = new T(); - _assetExporters.Add(assetExporter); + Log.EngineLogger.AssertDebug(_assetExporters.ContainsKey(T.ExportedAssetType), "Cannot register multiple exporters for one asset type."); + + _assetExporters.Add(T.ExportedAssetType, assetExporter); + } + + public IAssetImporter GetAssetImporter(StringView fileExtension) + { + if (_extensionToAssetImporter.TryGetValue(fileExtension, let importer)) + { + return importer; + } + + return null; + } + + public IAssetImporter GetAssetProcessor(Type importedResourceType) + { + if (_extensionToAssetImporter.TryGetValue(fileExtension, let importer)) + { + return importer; + } + + return null; } public void SetAsDefaultAssetLoader(params Span fileExtensions) where T : IAssetLoader @@ -332,14 +362,15 @@ class EditorContentManager : IContentManager } } - for (var i in _assetExporters) + // TODO: How do we get the exporter for the config? + /*for (var i in _assetExporters) { if (i.GetType() == typeof(TExport)) { exporter = i; break; } - } + }*/ _defaultAssetProcessors[foundExtension] = (importer, processor, exporter); } @@ -756,7 +787,7 @@ class EditorContentManager : IContentManager return result; } - + /* public IAssetExporter GetAssetExporter(AssetFile file) { IAssetExporter result = null; @@ -776,6 +807,16 @@ class EditorContentManager : IContentManager return result; } + */ + public IAssetExporter GetAssetExporter(AssetType assetType) + { + if (_assetExporters.TryGetValue(assetType, let exporter)) + { + return exporter; + } + + return null; + } public enum SaveAssetError { diff --git a/GlitchyEngine/src/Content/AssetType.bf b/GlitchyEngine/src/Content/AssetType.bf index 04c2e01..c069050 100644 --- a/GlitchyEngine/src/Content/AssetType.bf +++ b/GlitchyEngine/src/Content/AssetType.bf @@ -3,5 +3,6 @@ namespace GlitchyEngine.Content; enum AssetType : uint16 { Unknown, - Texture + Texture, + Sprite } \ No newline at end of file