mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 21: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 System.Collections;
|
||||||
using GlitchyEngine.Core;
|
using GlitchyEngine.Core;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace GlitchyEditor.Assets;
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
@@ -21,7 +22,9 @@ class CachedAsset
|
|||||||
public AssetType AssetType;
|
public AssetType AssetType;
|
||||||
public int64 CompressedByteCount;
|
public int64 CompressedByteCount;
|
||||||
public int64 UncompressedByteCount;
|
public int64 UncompressedByteCount;
|
||||||
public String AssetIdentifier ~ delete _;
|
public AssetIdentifier AssetIdentifier ~ delete _;
|
||||||
|
|
||||||
|
public int32 DataOffset;
|
||||||
|
|
||||||
public const String CacheFileExtension = ".laf";
|
public const String CacheFileExtension = ".laf";
|
||||||
}
|
}
|
||||||
@@ -93,6 +96,7 @@ class AssetCache
|
|||||||
Log.EngineLogger.Error($"Failed to read cached asset file \"filePath\".");
|
Log.EngineLogger.Error($"Failed to read cached asset file \"filePath\".");
|
||||||
|
|
||||||
delete cachedAsset;
|
delete cachedAsset;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
_assets.Add(cachedAsset.Handle, cachedAsset);
|
_assets.Add(cachedAsset.Handle, cachedAsset);
|
||||||
@@ -129,29 +133,101 @@ class AssetCache
|
|||||||
cachedAsset.CompressedByteCount = Try!(stream.Read<int64>());
|
cachedAsset.CompressedByteCount = Try!(stream.Read<int64>());
|
||||||
cachedAsset.UncompressedByteCount = 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);
|
String assetIdentifier = scope String(assetIdentifierByteCount);
|
||||||
cachedAsset.AssetIdentifier.PadLeft(assetIdentifierByteCount);
|
assetIdentifier.PadLeft(assetIdentifierByteCount);
|
||||||
Span<char8> charSpan = cachedAsset.AssetIdentifier;
|
Span<char8> charSpan = assetIdentifier;
|
||||||
int readBytes = Try!(stream.TryRead(Span<uint8>((uint8*)charSpan.Ptr, charSpan.Length)));
|
int readBytes = Try!(stream.TryRead(Span<uint8>((uint8*)charSpan.Ptr, charSpan.Length)));
|
||||||
|
|
||||||
|
cachedAsset.AssetIdentifier = new AssetIdentifier(assetIdentifier);
|
||||||
|
|
||||||
if (readBytes != assetIdentifierByteCount)
|
if (readBytes != assetIdentifierByteCount)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Warning($"Expected to read {assetIdentifierByteCount} bytes for the asset identifier, but read {readBytes} instead.");
|
Log.EngineLogger.Warning($"Expected to read {assetIdentifierByteCount} bytes for the asset identifier, but read {readBytes} instead.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cachedAsset.DataOffset = (.)stream.Position;
|
||||||
|
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedAsset GetCacheEntry(AssetHandle id)
|
public CachedAsset GetCacheEntry(AssetHandle assetHandle)
|
||||||
{
|
{
|
||||||
if (!_cacheLoaded)
|
if (!_cacheLoaded)
|
||||||
ReloadCache();
|
ReloadCache();
|
||||||
|
|
||||||
if (_assets.TryGetValue(id, let cachedAsset))
|
if (_assets.TryGetValue(assetHandle, let cachedAsset))
|
||||||
return cachedAsset;
|
return cachedAsset;
|
||||||
|
|
||||||
return null;
|
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 System.Collections;
|
||||||
using GlitchyEditor.Assets.Importers;
|
using GlitchyEditor.Assets.Importers;
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
namespace GlitchyEditor.Assets;
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
class AssetConverter
|
class AssetConverter
|
||||||
{
|
{
|
||||||
private append Queue<AssetFile> _queue = .() ~ delete:append _;
|
private append Queue<AssetFile> _queue = .();
|
||||||
|
|
||||||
private EditorContentManager _contentManager;
|
private EditorContentManager _contentManager;
|
||||||
|
|
||||||
@@ -36,15 +39,68 @@ class AssetConverter
|
|||||||
private void Process(AssetFile assetFile)
|
private void Process(AssetFile assetFile)
|
||||||
{
|
{
|
||||||
IAssetImporter importer = _contentManager.GetAssetImporter(assetFile);
|
IAssetImporter importer = _contentManager.GetAssetImporter(assetFile);
|
||||||
|
IAssetProcessor processor = _contentManager.GetAssetProcessor(assetFile);
|
||||||
|
IAssetExporter exporter = _contentManager.GetAssetExporter(assetFile);
|
||||||
|
|
||||||
if (importer == null)
|
if (importer == null)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error("Importer is 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);
|
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();
|
AssetProcessorConfig CreateDefaultConfig();
|
||||||
|
|
||||||
Result<Object> Process(ImportedResource importedResource, AssetProcessorConfig config);
|
Result<ProcessedResource> Process(ImportedResource importedResource, AssetProcessorConfig config);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IAssetExporter
|
interface IAssetExporter
|
||||||
|
|||||||
@@ -186,6 +186,9 @@ class TextureImporter : IAssetImporter
|
|||||||
surface.SlicePitch = 0;
|
surface.SlicePitch = 0;
|
||||||
surface.ArrayIndex = 0;
|
surface.ArrayIndex = 0;
|
||||||
surface.MipLevel = 0;
|
surface.MipLevel = 0;
|
||||||
|
surface.Width = width;
|
||||||
|
surface.Height = height;
|
||||||
|
surface.Depth = 1;
|
||||||
|
|
||||||
surfaces.Add(surface);
|
surfaces.Add(surface);
|
||||||
|
|
||||||
@@ -238,12 +241,14 @@ class TextureProcessorConfig : AssetProcessorConfig
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProcessedResource
|
abstract class ProcessedResource
|
||||||
{
|
{
|
||||||
private AssetIdentifier _assetIdentifier ~ delete _;
|
private AssetIdentifier _assetIdentifier ~ delete _;
|
||||||
|
|
||||||
public AssetIdentifier AssetIdentifier => _assetIdentifier;
|
public AssetIdentifier AssetIdentifier => _assetIdentifier;
|
||||||
|
|
||||||
|
public abstract AssetType AssetType {get;}
|
||||||
|
|
||||||
public this(AssetIdentifier ownAssetIdentifier)
|
public this(AssetIdentifier ownAssetIdentifier)
|
||||||
{
|
{
|
||||||
_assetIdentifier = ownAssetIdentifier;
|
_assetIdentifier = ownAssetIdentifier;
|
||||||
@@ -262,6 +267,8 @@ class ProcessedTexture : ProcessedResource
|
|||||||
public int Height = -1;
|
public int Height = -1;
|
||||||
public int Depth = -1;
|
public int Depth = -1;
|
||||||
|
|
||||||
|
public override AssetType AssetType => .Texture;
|
||||||
|
|
||||||
public class TextureSurface
|
public class TextureSurface
|
||||||
{
|
{
|
||||||
public uint8[] PixelData;
|
public uint8[] PixelData;
|
||||||
@@ -335,17 +342,23 @@ class ProcessedTexture : ProcessedResource
|
|||||||
|
|
||||||
public void SetSurfaceCount(int arraySize, int mipMapCount)
|
public void SetSurfaceCount(int arraySize, int mipMapCount)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.AssertDebug(arraySize > Surfaces.GetLength(0));
|
Log.EngineLogger.AssertDebug(Surfaces == null || arraySize > Surfaces.GetLength(0));
|
||||||
Log.EngineLogger.AssertDebug(mipMapCount > Surfaces.GetLength(1));
|
Log.EngineLogger.AssertDebug(Surfaces == null ||mipMapCount > Surfaces.GetLength(1));
|
||||||
|
|
||||||
|
ArraySize = arraySize;
|
||||||
|
MipMapCount = mipMapCount;
|
||||||
|
|
||||||
TextureSurface[,] oldSurfaces = Surfaces;
|
TextureSurface[,] oldSurfaces = Surfaces;
|
||||||
Surfaces = new TextureSurface[arraySize, mipMapCount];
|
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();
|
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(config is TextureProcessorConfig);
|
||||||
Log.EngineLogger.AssertDebug(importedObject is ImportedTexture);
|
Log.EngineLogger.AssertDebug(importedObject is ImportedTexture);
|
||||||
|
|
||||||
Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig));
|
return Try!(ProcessTexture(importedObject as ImportedTexture, config as TextureProcessorConfig));
|
||||||
|
|
||||||
return .Ok(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 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);
|
processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount);
|
||||||
|
|
||||||
for (LoadedSurface loadedSurface in importedTexture.Surfaces)
|
for (LoadedSurface loadedSurface in importedTexture.Surfaces)
|
||||||
@@ -390,7 +408,7 @@ class TextureProcessor : IAssetProcessor
|
|||||||
|
|
||||||
// TODO: Pack to BC-Format or what ever was selected.
|
// TODO: Pack to BC-Format or what ever was selected.
|
||||||
|
|
||||||
return .Ok;
|
return processedTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CalculateMipMapCount(int width, int height, int depth)
|
private int CalculateMipMapCount(int width, int height, int depth)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
private append AssetHierarchy _assetHierarchy = .(this);
|
private append AssetHierarchy _assetHierarchy = .(this);
|
||||||
private append AssetCache _assetCache = .() ~ delete:append _;
|
private append AssetCache _assetCache = .() ~ delete:append _;
|
||||||
private append AssetConverter _assetConverter = .(this) ~ delete:append _;
|
private append AssetConverter _assetConverter = .(this);
|
||||||
|
|
||||||
private append List<AssetHandle> _reloadQueue = .();
|
private append List<AssetHandle> _reloadQueue = .();
|
||||||
|
|
||||||
@@ -469,7 +469,14 @@ class EditorContentManager : IContentManager
|
|||||||
Log.EngineLogger.Error($"Could not find asset with handle {handle}.");
|
Log.EngineLogger.Error($"Could not find asset with handle {handle}.");
|
||||||
return .Invalid;
|
return .Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle);
|
||||||
|
|
||||||
|
if (cacheEntry != null)
|
||||||
|
{
|
||||||
|
// TODO: Load asset with new loaders
|
||||||
|
}
|
||||||
|
|
||||||
String filePath = scope String(resultNode->Value.Path);
|
String filePath = scope String(resultNode->Value.Path);
|
||||||
|
|
||||||
AssetNode assetNode = resultNode->Value;
|
AssetNode assetNode = resultNode->Value;
|
||||||
@@ -715,6 +722,46 @@ class EditorContentManager : IContentManager
|
|||||||
return result;
|
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
|
public enum SaveAssetError
|
||||||
{
|
{
|
||||||
case Unknown;
|
case Unknown;
|
||||||
|
|||||||
Reference in New Issue
Block a user