diff --git a/GlitchyEditor/src/Assets/AssetCache.bf b/GlitchyEditor/src/Assets/AssetCache.bf index 89f27dd..1335e5d 100644 --- a/GlitchyEditor/src/Assets/AssetCache.bf +++ b/GlitchyEditor/src/Assets/AssetCache.bf @@ -4,6 +4,7 @@ using System.IO; using System.Collections; using GlitchyEngine.Core; using GlitchyEngine.Content; +using System.IO; namespace GlitchyEditor.Assets; @@ -21,7 +22,9 @@ class CachedAsset public AssetType AssetType; public int64 CompressedByteCount; public int64 UncompressedByteCount; - public String AssetIdentifier ~ delete _; + public AssetIdentifier AssetIdentifier ~ delete _; + + public int32 DataOffset; public const String CacheFileExtension = ".laf"; } @@ -93,6 +96,7 @@ class AssetCache Log.EngineLogger.Error($"Failed to read cached asset file \"filePath\"."); delete cachedAsset; + continue; } _assets.Add(cachedAsset.Handle, cachedAsset); @@ -129,29 +133,101 @@ class AssetCache cachedAsset.CompressedByteCount = Try!(stream.Read()); cachedAsset.UncompressedByteCount = Try!(stream.Read()); - int32 assetIdentifierByteCount = Try!(stream.Read()); + int16 assetIdentifierByteCount = Try!(stream.Read()); - cachedAsset.AssetIdentifier = new String(assetIdentifierByteCount); - cachedAsset.AssetIdentifier.PadLeft(assetIdentifierByteCount); - Span charSpan = cachedAsset.AssetIdentifier; + String assetIdentifier = scope String(assetIdentifierByteCount); + assetIdentifier.PadLeft(assetIdentifierByteCount); + Span charSpan = assetIdentifier; int readBytes = Try!(stream.TryRead(Span((uint8*)charSpan.Ptr, charSpan.Length))); + cachedAsset.AssetIdentifier = new AssetIdentifier(assetIdentifier); + if (readBytes != assetIdentifierByteCount) { Log.EngineLogger.Warning($"Expected to read {assetIdentifierByteCount} bytes for the asset identifier, but read {readBytes} instead."); } + cachedAsset.DataOffset = (.)stream.Position; + return .Ok; } - public CachedAsset GetCacheEntry(AssetHandle id) + public CachedAsset GetCacheEntry(AssetHandle assetHandle) { if (!_cacheLoaded) ReloadCache(); - if (_assets.TryGetValue(id, let cachedAsset)) + if (_assets.TryGetValue(assetHandle, let cachedAsset)) return cachedAsset; return null; } + + private void GetCacheFilePath(AssetHandle handle, String outFilePath) + { + outFilePath.Append(_directory); + outFilePath.Append(Path.DirectorySeparatorChar); + outFilePath.Append(handle); + outFilePath.Append(CachedAsset.CacheFileExtension); + } + + public Result SaveAsset(CachedAsset assetInfo, Span data) + { + CachedAsset asset = GetCacheEntry(assetInfo.Handle); + + if (asset == null) + { + asset = new CachedAsset(); + asset.Handle = assetInfo.Handle; + asset.FilePath = new String(128); + GetCacheFilePath(asset.Handle, asset.FilePath); + _assets[asset.Handle] = asset; + } + + delete asset.AssetIdentifier; + asset.AssetIdentifier = new AssetIdentifier(assetInfo.AssetIdentifier); + + asset.FormatVersion = FormatVersion; + asset.Compression = assetInfo.Compression; + asset.AssetType = assetInfo.AssetType; + asset.CreationTimestamp = assetInfo.CreationTimestamp; + + asset.UncompressedByteCount = data.Length; + + Span dataToWrite; + + switch (asset.Compression) + { + case .L4Z: + // TODO: L4Z + Runtime.NotImplemented(); + // asset.CompressedByteCount = compressedData.Length; + case .None: + asset.CompressedByteCount = data.Length; + dataToWrite = data; + } + + FileStream writer = scope .(); + Try!(writer.Create(asset.FilePath, .Write, .None)); + + Try!(writer.Write(CachedAsset.MagicWord)); + Try!(writer.Write(FormatVersion)); + Try!(writer.Write(asset.Handle)); + Try!(writer.Write(asset.CreationTimestamp)); + Try!(writer.Write(asset.Compression)); + Try!(writer.Write(asset.AssetType)); + Try!(writer.Write(asset.CompressedByteCount)); + Try!(writer.Write(asset.UncompressedByteCount)); + + Try!(writer.Write((int16)asset.AssetIdentifier.FullIdentifier.Length)); + Try!(writer.Write(asset.AssetIdentifier.FullIdentifier)); + + asset.DataOffset = (.)writer.Position; + + Try!(writer.Write(dataToWrite)); + + // TODO: Notify content manager! + + return .Ok; + } } \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/AssetConverter.bf b/GlitchyEditor/src/Assets/AssetConverter.bf index 197f5f2..6438f15 100644 --- a/GlitchyEditor/src/Assets/AssetConverter.bf +++ b/GlitchyEditor/src/Assets/AssetConverter.bf @@ -1,12 +1,15 @@ using System.Collections; using GlitchyEditor.Assets.Importers; using GlitchyEngine; +using System; +using System.IO; +using GlitchyEngine.Content; namespace GlitchyEditor.Assets; class AssetConverter { - private append Queue _queue = .() ~ delete:append _; + private append Queue _queue = .(); private EditorContentManager _contentManager; @@ -36,15 +39,68 @@ class AssetConverter private void Process(AssetFile assetFile) { IAssetImporter importer = _contentManager.GetAssetImporter(assetFile); + IAssetProcessor processor = _contentManager.GetAssetProcessor(assetFile); + IAssetExporter exporter = _contentManager.GetAssetExporter(assetFile); if (importer == null) { Log.EngineLogger.Error("Importer is null!"); + return; + } + + if (processor == null) + { + Log.EngineLogger.Error("Processor is null!"); + return; + } + + if (exporter == null) + { + Log.EngineLogger.Error("Exporter is null!"); + return; } - ImportedResource importedResource = importer.Import(assetFile.AssetFile.Path, + Result importResult = importer.Import(assetFile.AssetFile.Path, assetFile.AssetFile.Identifier, assetFile.AssetConfig.ImporterConfig); - delete importedResource; + if (importResult case .Err) + { + Log.EngineLogger.Error("Failed to import asset!"); + return; + } + + defer { delete importResult.Value; } + + Result processResult = processor.Process(importResult.Value, assetFile.AssetConfig.ProcessorConfig); + + if (processResult case .Err) + { + Log.EngineLogger.Error("Failed to process asset!"); + return; + } + + defer { delete processResult.Value; } + + MemoryStream memoryStream = scope .(); + + Result exportResult = exporter.Export(memoryStream, processResult.Value, assetFile.AssetConfig.ExporterConfig); + + if (exportResult case .Err) + { + Log.EngineLogger.Error("Failed to export asset!"); + return; + } + + CachedAsset assetInfo = scope CachedAsset(); + assetInfo.Handle = assetFile.AssetConfig.AssetHandle; + assetInfo.CreationTimestamp = DateTime.UtcNow; + assetInfo.Compression = assetFile.AssetConfig.ExporterConfig.Compression; + assetInfo.AssetIdentifier = new AssetIdentifier(assetFile.AssetFile.Identifier); + assetInfo.AssetType = processResult.Value.AssetType; + + if (_contentManager.AssetCache.SaveAsset(assetInfo, memoryStream.Memory) case .Err) + { + Log.EngineLogger.Error("Failed to write asset to cache."); + } } } \ No newline at end of file diff --git a/GlitchyEditor/src/Assets/Importers/Interfaces.bf b/GlitchyEditor/src/Assets/Importers/Interfaces.bf index dd79549..6b9af64 100644 --- a/GlitchyEditor/src/Assets/Importers/Interfaces.bf +++ b/GlitchyEditor/src/Assets/Importers/Interfaces.bf @@ -18,7 +18,7 @@ interface IAssetProcessor { AssetProcessorConfig CreateDefaultConfig(); - Result Process(ImportedResource importedResource, AssetProcessorConfig config); + Result Process(ImportedResource importedResource, AssetProcessorConfig config); } interface IAssetExporter diff --git a/GlitchyEditor/src/Assets/Importers/TextureImporter.bf b/GlitchyEditor/src/Assets/Importers/TextureImporter.bf index 143250e..b0fb416 100644 --- a/GlitchyEditor/src/Assets/Importers/TextureImporter.bf +++ b/GlitchyEditor/src/Assets/Importers/TextureImporter.bf @@ -186,6 +186,9 @@ class TextureImporter : IAssetImporter surface.SlicePitch = 0; surface.ArrayIndex = 0; surface.MipLevel = 0; + surface.Width = width; + surface.Height = height; + surface.Depth = 1; surfaces.Add(surface); @@ -238,12 +241,14 @@ class TextureProcessorConfig : AssetProcessorConfig } } -class ProcessedResource +abstract class ProcessedResource { private AssetIdentifier _assetIdentifier ~ delete _; public AssetIdentifier AssetIdentifier => _assetIdentifier; + public abstract AssetType AssetType {get;} + public this(AssetIdentifier ownAssetIdentifier) { _assetIdentifier = ownAssetIdentifier; @@ -262,6 +267,8 @@ class ProcessedTexture : ProcessedResource public int Height = -1; public int Depth = -1; + public override AssetType AssetType => .Texture; + public class TextureSurface { public uint8[] PixelData; @@ -335,17 +342,23 @@ class ProcessedTexture : ProcessedResource public void SetSurfaceCount(int arraySize, int mipMapCount) { - Log.EngineLogger.AssertDebug(arraySize > Surfaces.GetLength(0)); - Log.EngineLogger.AssertDebug(mipMapCount > Surfaces.GetLength(1)); + Log.EngineLogger.AssertDebug(Surfaces == null || arraySize > Surfaces.GetLength(0)); + Log.EngineLogger.AssertDebug(Surfaces == null ||mipMapCount > Surfaces.GetLength(1)); + + ArraySize = arraySize; + MipMapCount = mipMapCount; TextureSurface[,] oldSurfaces = Surfaces; Surfaces = new TextureSurface[arraySize, mipMapCount]; - - for (int i < oldSurfaces.GetLength(0)) + + if (oldSurfaces != null) { - for (int j < oldSurfaces.GetLength(1)) + for (int i < oldSurfaces.GetLength(0)) { - Surfaces[i, j] = oldSurfaces[i, j]; + for (int j < oldSurfaces.GetLength(1)) + { + Surfaces[i, j] = oldSurfaces[i, j]; + } } } } @@ -358,20 +371,25 @@ class TextureProcessor : IAssetProcessor return new TextureProcessorConfig(); } - public Result Process(ImportedResource importedObject, AssetProcessorConfig config) + public Result Process(ImportedResource importedObject, AssetProcessorConfig config) { Log.EngineLogger.AssertDebug(config is TextureProcessorConfig); Log.EngineLogger.AssertDebug(importedObject is ImportedTexture); - Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig)); - - return .Ok(null); + return Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig)); } - private Result ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config) + private Result ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config) { ProcessedTexture processedTexture = new ProcessedTexture(new AssetIdentifier(importedTexture.AssetIdentifier.FullIdentifier)); + processedTexture.Dimension = importedTexture.TextureInfo.Dimension; + processedTexture.PixelFormat = (.)importedTexture.TextureInfo.PixelFormat; + processedTexture.IsCubeMap = importedTexture.TextureInfo.IsCubeMap; + processedTexture.Width = importedTexture.TextureInfo.Width; + processedTexture.Height = importedTexture.TextureInfo.Height; + processedTexture.Depth = importedTexture.TextureInfo.Depth; + processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount); for (LoadedSurface loadedSurface in importedTexture.Surfaces) @@ -390,7 +408,7 @@ class TextureProcessor : IAssetProcessor // TODO: Pack to BC-Format or what ever was selected. - return .Ok; + return processedTexture; } private int CalculateMipMapCount(int width, int height, int depth) diff --git a/GlitchyEditor/src/EditorContentManager.bf b/GlitchyEditor/src/EditorContentManager.bf index f310b8c..010e33b 100644 --- a/GlitchyEditor/src/EditorContentManager.bf +++ b/GlitchyEditor/src/EditorContentManager.bf @@ -27,7 +27,7 @@ class EditorContentManager : IContentManager private append AssetHierarchy _assetHierarchy = .(this); private append AssetCache _assetCache = .() ~ delete:append _; - private append AssetConverter _assetConverter = .(this) ~ delete:append _; + private append AssetConverter _assetConverter = .(this); private append List _reloadQueue = .(); @@ -469,7 +469,14 @@ class EditorContentManager : IContentManager Log.EngineLogger.Error($"Could not find asset with handle {handle}."); return .Invalid; } - + + CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle); + + if (cacheEntry != null) + { + // TODO: Load asset with new loaders + } + String filePath = scope String(resultNode->Value.Path); AssetNode assetNode = resultNode->Value; @@ -715,6 +722,46 @@ class EditorContentManager : IContentManager return result; } + public IAssetProcessor GetAssetProcessor(AssetFile file) + { + IAssetProcessor result = null; + + String typeName = scope .(128); + + for (IAssetProcessor processor in _assetProcessors) + { + processor.GetType().GetName(typeName..Clear()); + + if (typeName == file.AssetConfig.Processor) + { + result = processor; + break; + } + } + + return result; + } + + public IAssetExporter GetAssetExporter(AssetFile file) + { + IAssetExporter result = null; + + String typeName = scope .(128); + + for (IAssetExporter exporter in _assetExporters) + { + exporter.GetType().GetName(typeName..Clear()); + + if (typeName == file.AssetConfig.Exporter) + { + result = exporter; + break; + } + } + + return result; + } + public enum SaveAssetError { case Unknown;