mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Convert texture asset and save to cache
This commit is contained in:
@@ -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<int64>());
|
||||
cachedAsset.UncompressedByteCount = Try!(stream.Read<int64>());
|
||||
|
||||
int32 assetIdentifierByteCount = Try!(stream.Read<int32>());
|
||||
int16 assetIdentifierByteCount = Try!(stream.Read<int16>());
|
||||
|
||||
cachedAsset.AssetIdentifier = new String(assetIdentifierByteCount);
|
||||
cachedAsset.AssetIdentifier.PadLeft(assetIdentifierByteCount);
|
||||
Span<char8> charSpan = cachedAsset.AssetIdentifier;
|
||||
String assetIdentifier = scope String(assetIdentifierByteCount);
|
||||
assetIdentifier.PadLeft(assetIdentifierByteCount);
|
||||
Span<char8> charSpan = assetIdentifier;
|
||||
int readBytes = Try!(stream.TryRead(Span<uint8>((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<void> SaveAsset(CachedAsset assetInfo, Span<uint8> 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<uint8> 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<char8[3]>(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<int64>(asset.CompressedByteCount));
|
||||
Try!(writer.Write<int64>(asset.UncompressedByteCount));
|
||||
|
||||
Try!(writer.Write<int16>((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;
|
||||
}
|
||||
}
|
||||
@@ -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<AssetFile> _queue = .() ~ delete:append _;
|
||||
private append Queue<AssetFile> _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<ImportedResource> 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<ProcessedResource> 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<void> 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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ interface IAssetProcessor
|
||||
{
|
||||
AssetProcessorConfig CreateDefaultConfig();
|
||||
|
||||
Result<Object> Process(ImportedResource importedResource, AssetProcessorConfig config);
|
||||
Result<ProcessedResource> Process(ImportedResource importedResource, AssetProcessorConfig config);
|
||||
}
|
||||
|
||||
interface IAssetExporter
|
||||
|
||||
@@ -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<Object> Process(ImportedResource importedObject, AssetProcessorConfig config)
|
||||
public Result<ProcessedResource> 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<void> ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config)
|
||||
private Result<ProcessedTexture> 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)
|
||||
|
||||
@@ -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<AssetHandle> _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;
|
||||
|
||||
Reference in New Issue
Block a user