mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Start of asset management 2.0
This commit is contained in:
@@ -3,6 +3,8 @@ using GlitchyEngine;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using Bon;
|
using Bon;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
|
using GlitchyEditor.Assets;
|
||||||
|
using GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
namespace GlitchyEditor;
|
namespace GlitchyEditor;
|
||||||
|
|
||||||
@@ -18,28 +20,39 @@ class AssetConfig
|
|||||||
[BonInclude]
|
[BonInclude]
|
||||||
public AssetLoaderConfig Config ~ delete _;
|
public AssetLoaderConfig Config ~ delete _;
|
||||||
|
|
||||||
|
[BonInclude]
|
||||||
|
public String Importer ~ delete _;
|
||||||
|
[BonInclude]
|
||||||
|
public AssetImporterConfig ImporterConfig ~ delete _;
|
||||||
|
[BonInclude]
|
||||||
|
public String Processor ~ delete _;
|
||||||
|
[BonInclude]
|
||||||
|
public AssetProcessorConfig ProcessorConfig ~ delete _;
|
||||||
|
[BonInclude]
|
||||||
|
public String Exporter ~ delete _;
|
||||||
|
[BonInclude]
|
||||||
|
public AssetExporterConfig ExporterConfig ~ delete _;
|
||||||
|
|
||||||
[BonInclude]
|
[BonInclude]
|
||||||
public AssetHandle AssetHandle = .Invalid;
|
public AssetHandle AssetHandle = .Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents an unprocessed asset as it lies in the asset hierarchy.
|
||||||
class AssetFile
|
class AssetFile
|
||||||
{
|
{
|
||||||
private EditorContentManager _contentManager;
|
private EditorContentManager _contentManager;
|
||||||
|
|
||||||
private String _path ~ delete:append _;
|
|
||||||
private String _identifier ~ delete:append _;
|
|
||||||
private String _assetConfigPath ~ delete:append _;
|
private String _assetConfigPath ~ delete:append _;
|
||||||
|
private AssetNode _assetFile;
|
||||||
|
|
||||||
private AssetConfig _assetConfig ~ delete _;
|
private AssetConfig _assetConfig ~ delete _;
|
||||||
|
|
||||||
private bool _isDirectory;
|
|
||||||
|
|
||||||
private Asset _loadedAsset;
|
private Asset _loadedAsset;
|
||||||
|
|
||||||
public bool IsDirectory => _isDirectory;
|
private DateTime _lastAssetEditTime;
|
||||||
|
private DateTime _lastConfigEditTime;
|
||||||
|
|
||||||
public StringView FilePath => _path;
|
public AssetNode AssetFile => _assetFile;
|
||||||
public StringView Identifier => _identifier;
|
|
||||||
public StringView AssetConfigPath => _assetConfigPath;
|
public StringView AssetConfigPath => _assetConfigPath;
|
||||||
|
|
||||||
public const String ConfigFileExtension = ".ass";
|
public const String ConfigFileExtension = ".ass";
|
||||||
@@ -48,30 +61,47 @@ class AssetFile
|
|||||||
|
|
||||||
public Asset LoadedAsset => _loadedAsset;
|
public Asset LoadedAsset => _loadedAsset;
|
||||||
|
|
||||||
|
public EditorContentManager ContentManager => _contentManager;
|
||||||
|
|
||||||
[AllowAppend]
|
[AllowAppend]
|
||||||
public this(EditorContentManager contentManager, StringView identifier, StringView path, bool isDirectory)
|
public this(EditorContentManager contentManager, AssetNode assetNode)
|
||||||
{
|
{
|
||||||
String identifierBuffer = append String(identifier);
|
String configPathBuffer = append String(assetNode.Path.Length + ConfigFileExtension.Length);
|
||||||
String pathBuffer = append String(path);
|
|
||||||
String configPathBuffer = append String(path.Length + ConfigFileExtension.Length);
|
|
||||||
|
|
||||||
_identifier = identifierBuffer;
|
configPathBuffer..Append(assetNode.Path).Append(ConfigFileExtension);
|
||||||
_path = pathBuffer;
|
|
||||||
|
|
||||||
configPathBuffer..Append(path).Append(ConfigFileExtension);
|
|
||||||
_assetConfigPath = configPathBuffer;
|
_assetConfigPath = configPathBuffer;
|
||||||
|
|
||||||
_contentManager = contentManager;
|
_contentManager = contentManager;
|
||||||
|
|
||||||
_isDirectory = isDirectory;
|
_assetFile = assetNode;
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(File.Exists(_path), "File doesn't exist.");
|
_lastAssetEditTime = File.GetLastWriteTimeUtc(_assetFile.Path);
|
||||||
|
|
||||||
FindAssetConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loads the asset config (.ass) file or creates it.
|
public static AssetFile LoadOrCreateAssetFile(EditorContentManager contentManager, AssetNode assetNode)
|
||||||
private void FindAssetConfig()
|
{
|
||||||
|
AssetFile assetFile = new AssetFile(contentManager, assetNode);
|
||||||
|
|
||||||
|
assetFile.LoadOrCreateAssetConfig();
|
||||||
|
|
||||||
|
// TODO: Remove this check once we only use the new processing pipeline
|
||||||
|
if (assetFile._assetConfig.ImporterConfig != null)
|
||||||
|
{
|
||||||
|
CachedAsset cacheEntry = assetFile._contentManager.AssetCache.GetCacheEntry(assetFile._assetConfig.AssetHandle);
|
||||||
|
|
||||||
|
if (cacheEntry == null ||
|
||||||
|
cacheEntry.CreationTimestamp < assetFile._lastAssetEditTime ||
|
||||||
|
cacheEntry.CreationTimestamp < assetFile._lastConfigEditTime)
|
||||||
|
{
|
||||||
|
assetFile._contentManager.AssetConverter.QueueForProcessing(assetFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return assetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Loads the asset config (.ass) file or creates it.
|
||||||
|
private void LoadOrCreateAssetConfig()
|
||||||
{
|
{
|
||||||
if (File.Exists(_assetConfigPath))
|
if (File.Exists(_assetConfigPath))
|
||||||
{
|
{
|
||||||
@@ -81,6 +111,8 @@ class AssetFile
|
|||||||
{
|
{
|
||||||
CreateDefaultAssetLoader();
|
CreateDefaultAssetLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lastAssetEditTime = File.GetLastWriteTimeUtc(_assetConfigPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GenerateAssetHandle()
|
private void GenerateAssetHandle()
|
||||||
@@ -90,12 +122,18 @@ class AssetFile
|
|||||||
|
|
||||||
private void CreateDefaultAssetLoader()
|
private void CreateDefaultAssetLoader()
|
||||||
{
|
{
|
||||||
String fileExtension = Path.GetExtension(_path, .. scope .());
|
String fileExtension = Path.GetExtension(_assetFile.Path, .. scope .());
|
||||||
|
|
||||||
_assetConfig = new AssetConfig();
|
_assetConfig = new AssetConfig();
|
||||||
|
|
||||||
GenerateAssetHandle();
|
GenerateAssetHandle();
|
||||||
|
|
||||||
|
var assetPipeline = _contentManager.GetDefaultProcessors(fileExtension);
|
||||||
|
|
||||||
|
// TODO!
|
||||||
|
//if (assetPipeline case .Err)
|
||||||
|
// return;
|
||||||
|
|
||||||
var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension);
|
var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension);
|
||||||
|
|
||||||
// We don't have a loader -> we don't need a config
|
// We don't have a loader -> we don't need a config
|
||||||
@@ -108,6 +146,17 @@ class AssetFile
|
|||||||
_assetConfig.Config = assetLoader?.GetDefaultConfig();
|
_assetConfig.Config = assetLoader?.GetDefaultConfig();
|
||||||
_assetConfig.Config?.[Friend]_changed = true;
|
_assetConfig.Config?.[Friend]_changed = true;
|
||||||
|
|
||||||
|
_assetConfig.Importer = new String();
|
||||||
|
assetPipeline?.Importer?.GetType()?.GetName(_assetConfig.Importer);
|
||||||
|
_assetConfig.ImporterConfig = assetPipeline?.Importer.CreateDefaultConfig();
|
||||||
|
|
||||||
|
_assetConfig.Processor = new String();
|
||||||
|
assetPipeline?.Processor?.GetType()?.GetName(_assetConfig.Processor);
|
||||||
|
_assetConfig.ProcessorConfig = assetPipeline?.Processor.CreateDefaultConfig();
|
||||||
|
|
||||||
|
_assetConfig.Exporter = new String();
|
||||||
|
assetPipeline?.Exporter?.GetType()?.GetName(_assetConfig.Exporter);
|
||||||
|
_assetConfig.ExporterConfig = assetPipeline?.Exporter.CreateDefaultConfig();
|
||||||
|
|
||||||
SaveAssetConfig();
|
SaveAssetConfig();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
|
/// Represents a processed asset file as it lies in the cache-directory.
|
||||||
|
class CachedAsset
|
||||||
|
{
|
||||||
|
public const char8[3] MagicWord = .('L', 'A', 'F');
|
||||||
|
|
||||||
|
public String FilePath ~ delete _;
|
||||||
|
|
||||||
|
public uint16 FormatVersion;
|
||||||
|
public AssetHandle Handle;
|
||||||
|
public DateTime CreationTimestamp;
|
||||||
|
public AssetCompression Compression;
|
||||||
|
public AssetType AssetType;
|
||||||
|
public int64 CompressedByteCount;
|
||||||
|
public int64 UncompressedByteCount;
|
||||||
|
public String AssetIdentifier ~ delete _;
|
||||||
|
|
||||||
|
public const String CacheFileExtension = ".laf";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Manages the cache for already processed assets
|
||||||
|
class AssetCache
|
||||||
|
{
|
||||||
|
/// Current format version of loose asset file (.laf) file reader and writer.
|
||||||
|
public const uint16 FormatVersion = 1;
|
||||||
|
|
||||||
|
private append String _directory = .() ~ delete:append _;
|
||||||
|
|
||||||
|
private append Dictionary<AssetHandle, CachedAsset> _assets ~ delete:append _;
|
||||||
|
|
||||||
|
public StringView CacheDirectory => _directory;
|
||||||
|
|
||||||
|
private bool _cacheLoaded;
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearCache()
|
||||||
|
{
|
||||||
|
_cacheLoaded = false;
|
||||||
|
ClearDictionaryAndDeleteValues!(_assets);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the directory in which the processed assets are cached.
|
||||||
|
public void SetDirectory(StringView directory)
|
||||||
|
{
|
||||||
|
_directory.Set(directory);
|
||||||
|
ReloadCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: This might take ages for large projects and definitely shouldn't run in the main thread!
|
||||||
|
public void ReloadCache()
|
||||||
|
{
|
||||||
|
ClearCache();
|
||||||
|
|
||||||
|
if (!Directory.Exists(_directory))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Info($"Asset cache directory doesn't exist, creating directory \"{_directory}\"...");
|
||||||
|
|
||||||
|
if (Directory.CreateDirectory(_directory) case .Err(let error))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Critical($"Failed to create cache directory \"{_directory}\". Reason: {error}.");
|
||||||
|
Log.EngineLogger.Critical($"The engine will not function properly without the asset cache directory. Save your project and restart the engine.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point we either just created the cache directory and thus it's empty,
|
||||||
|
// or we failed and can't do anything anyway.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String filePath = scope .();
|
||||||
|
for (FileFindEntry file in Directory.EnumerateFiles(_directory))
|
||||||
|
{
|
||||||
|
filePath.Clear();
|
||||||
|
file.GetFilePath(filePath);
|
||||||
|
|
||||||
|
if (!filePath.EndsWith(CachedAsset.CacheFileExtension, .OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CachedAsset cachedAsset = new .();
|
||||||
|
if (ReadAssetFile(filePath, cachedAsset) case .Err)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to read cached asset file \"filePath\".");
|
||||||
|
|
||||||
|
delete cachedAsset;
|
||||||
|
}
|
||||||
|
|
||||||
|
_assets.Add(cachedAsset.Handle, cachedAsset);
|
||||||
|
}
|
||||||
|
|
||||||
|
_cacheLoaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<void> ReadAssetFile(StringView filePath, CachedAsset cachedAsset)
|
||||||
|
{
|
||||||
|
cachedAsset.FilePath = new String(filePath);
|
||||||
|
|
||||||
|
FileStream stream = scope .();
|
||||||
|
Try!(stream.Open(filePath));
|
||||||
|
|
||||||
|
// Check magic word
|
||||||
|
char8[3] magicWord = Try!(stream.Read<char8[3]>());
|
||||||
|
if (magicWord != CachedAsset.MagicWord)
|
||||||
|
return .Err;
|
||||||
|
|
||||||
|
cachedAsset.FormatVersion = Try!(stream.Read<uint16>());
|
||||||
|
|
||||||
|
// Validate format version
|
||||||
|
if (cachedAsset.FormatVersion == 0 || cachedAsset.FormatVersion > FormatVersion)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error("The cached assets version is either invalid or too new.");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedAsset.Handle = Try!(stream.Read<AssetHandle>());
|
||||||
|
cachedAsset.CreationTimestamp = Try!(stream.Read<DateTime>());
|
||||||
|
cachedAsset.Compression = Try!(stream.Read<AssetCompression>());
|
||||||
|
cachedAsset.AssetType = Try!(stream.Read<AssetType>());
|
||||||
|
cachedAsset.CompressedByteCount = Try!(stream.Read<int64>());
|
||||||
|
cachedAsset.UncompressedByteCount = Try!(stream.Read<int64>());
|
||||||
|
|
||||||
|
int32 assetIdentifierByteCount = Try!(stream.Read<int32>());
|
||||||
|
|
||||||
|
cachedAsset.AssetIdentifier = new String(assetIdentifierByteCount);
|
||||||
|
cachedAsset.AssetIdentifier.PadLeft(assetIdentifierByteCount);
|
||||||
|
Span<char8> charSpan = cachedAsset.AssetIdentifier;
|
||||||
|
int readBytes = Try!(stream.TryRead(Span<uint8>((uint8*)charSpan.Ptr, charSpan.Length)));
|
||||||
|
|
||||||
|
if (readBytes != assetIdentifierByteCount)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Warning($"Expected to read {assetIdentifierByteCount} bytes for the asset identifier, but read {readBytes} instead.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CachedAsset GetCacheEntry(AssetHandle id)
|
||||||
|
{
|
||||||
|
if (!_cacheLoaded)
|
||||||
|
ReloadCache();
|
||||||
|
|
||||||
|
if (_assets.TryGetValue(id, let cachedAsset))
|
||||||
|
return cachedAsset;
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using GlitchyEditor.Assets.Importers;
|
||||||
|
using GlitchyEngine;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
|
class AssetConverter
|
||||||
|
{
|
||||||
|
private append Queue<AssetFile> _queue = .() ~ delete:append _;
|
||||||
|
|
||||||
|
private EditorContentManager _contentManager;
|
||||||
|
|
||||||
|
public this(EditorContentManager contentManager)
|
||||||
|
{
|
||||||
|
_contentManager = contentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void QueueForProcessing(AssetFile assetFile)
|
||||||
|
{
|
||||||
|
_queue.Add(assetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
if (_queue.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (AssetFile assetFile in _queue)
|
||||||
|
{
|
||||||
|
Process(assetFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
_queue.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Process(AssetFile assetFile)
|
||||||
|
{
|
||||||
|
IAssetImporter importer = _contentManager.GetAssetImporter(assetFile);
|
||||||
|
|
||||||
|
if (importer == null)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error("Importer is null!");
|
||||||
|
}
|
||||||
|
|
||||||
|
ImportedResource importedResource = importer.Import(assetFile.AssetFile.Path,
|
||||||
|
assetFile.AssetFile.Identifier, assetFile.AssetConfig.ImporterConfig);
|
||||||
|
|
||||||
|
delete importedResource;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -439,11 +439,11 @@ class AssetHierarchy
|
|||||||
// Only files get AssetFile and AssetHandle
|
// Only files get AssetFile and AssetHandle
|
||||||
if (!isDirectory)
|
if (!isDirectory)
|
||||||
{
|
{
|
||||||
// TODO: Subassets
|
// TODO: Subassets -> Happens in processor!
|
||||||
//GrabSubAssets(node);
|
//GrabSubAssets(node);
|
||||||
|
|
||||||
// TODO: Apparently directories were supposed to get an AssetFile? Makes sense, we wanted to have settings for directories, too!
|
// TODO: Apparently directories were supposed to get an AssetFile? Makes sense, we wanted to have settings for directories, too!
|
||||||
treeNode->AssetFile = new AssetFile(_contentManager, assetNode.Identifier, assetNode.Path, assetNode.IsDirectory);
|
treeNode->AssetFile = AssetFile.LoadOrCreateAssetFile(_contentManager, assetNode);
|
||||||
|
|
||||||
_handleToAssetNode.Add(assetNode.AssetFile.AssetConfig.AssetHandle, treeNode);
|
_handleToAssetNode.Add(assetNode.AssetFile.AssetConfig.AssetHandle, treeNode);
|
||||||
}
|
}
|
||||||
@@ -598,10 +598,10 @@ class AssetHierarchy
|
|||||||
// Directories have no AssetFile?
|
// Directories have no AssetFile?
|
||||||
if (node->AssetFile != null)
|
if (node->AssetFile != null)
|
||||||
{
|
{
|
||||||
node->AssetFile.[Friend]_path.Set(node->Path);
|
node->Path.Set(newFilePath);
|
||||||
|
|
||||||
node->AssetFile.[Friend]_identifier.Set(newFilePath);
|
delete node->Identifier;
|
||||||
AssetIdentifier.Fixup(node->AssetFile.[Friend]_identifier);
|
node->Identifier = new AssetIdentifier(newFilePath);
|
||||||
|
|
||||||
node->AssetFile.[Friend]_assetConfigPath.Set(node->Path);
|
node->AssetFile.[Friend]_assetConfigPath.Set(node->Path);
|
||||||
node->AssetFile.[Friend]_assetConfigPath.Append(AssetFile.ConfigFileExtension);
|
node->AssetFile.[Friend]_assetConfigPath.Append(AssetFile.ConfigFileExtension);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using GlitchyEngine.Renderer;
|
|||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
namespace GlitchyEditor.Assets;
|
namespace GlitchyEditor.Assets;
|
||||||
|
|
||||||
|
// TODO: Why exactly are AssetFile and AssetNode separated?
|
||||||
public class AssetNode
|
public class AssetNode
|
||||||
{
|
{
|
||||||
public String Name ~ delete _;
|
public String Name ~ delete _;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
using Bon;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
abstract class Config
|
||||||
|
{
|
||||||
|
[BonIgnore]
|
||||||
|
protected bool _changed;
|
||||||
|
|
||||||
|
public bool Changed => _changed;
|
||||||
|
|
||||||
|
protected bool SetIfChanged<T>(ref T field, T value)
|
||||||
|
{
|
||||||
|
if (field == value)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
field = value;
|
||||||
|
_changed = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
class AssetImporterConfig : Config
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
class AssetProcessorConfig : Config
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
class AssetExporterConfig : Config
|
||||||
|
{
|
||||||
|
[BonInclude]
|
||||||
|
private AssetCompression _compression;
|
||||||
|
|
||||||
|
public AssetCompression Compression
|
||||||
|
{
|
||||||
|
get => _compression;
|
||||||
|
set => SetIfChanged(ref _compression, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,6 +16,10 @@ public struct LoadedSurface
|
|||||||
public int ArrayIndex;
|
public int ArrayIndex;
|
||||||
public int CubeFace;
|
public int CubeFace;
|
||||||
public int MipLevel;
|
public int MipLevel;
|
||||||
|
|
||||||
|
public uint32 Width;
|
||||||
|
public uint32 Height;
|
||||||
|
public uint32 Depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct LoadedTextureInfo
|
public struct LoadedTextureInfo
|
||||||
@@ -703,6 +707,10 @@ static class DdsImporter
|
|||||||
surface.CubeFace = cubeFace;
|
surface.CubeFace = cubeFace;
|
||||||
surface.MipLevel = mipLevel;
|
surface.MipLevel = mipLevel;
|
||||||
|
|
||||||
|
surface.Width = width;
|
||||||
|
surface.Height = height;
|
||||||
|
surface.Depth = depth;
|
||||||
|
|
||||||
surfaces.Add(surface);
|
surfaces.Add(surface);
|
||||||
|
|
||||||
++index;
|
++index;
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.IO;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
|
interface IAssetImporter
|
||||||
|
{
|
||||||
|
static List<StringView> FileExtensions {get;}
|
||||||
|
|
||||||
|
AssetImporterConfig CreateDefaultConfig();
|
||||||
|
|
||||||
|
Result<ImportedResource> Import(StringView fullFileName, AssetIdentifier assetIdentifier, AssetImporterConfig config);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAssetProcessor
|
||||||
|
{
|
||||||
|
AssetProcessorConfig CreateDefaultConfig();
|
||||||
|
|
||||||
|
Result<Object> Process(ImportedResource importedResource, AssetProcessorConfig config);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IAssetExporter
|
||||||
|
{
|
||||||
|
AssetExporterConfig CreateDefaultConfig();
|
||||||
|
|
||||||
|
Result<void> Export(Stream stream, ProcessedResource processedObject, AssetExporterConfig config);
|
||||||
|
}
|
||||||
@@ -0,0 +1,609 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.IO;
|
||||||
|
using Bon;
|
||||||
|
using GlitchyEngine.Content;
|
||||||
|
using GlitchyEngine;
|
||||||
|
using GlitchyEngine.Renderer;
|
||||||
|
using static GlitchyEditor.Assets.Importers.LoadedTextureInfo;
|
||||||
|
|
||||||
|
namespace GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
|
class ImportedResource
|
||||||
|
{
|
||||||
|
private AssetIdentifier _assetIdentifier ~ delete _;
|
||||||
|
|
||||||
|
public AssetIdentifier AssetIdentifier => _assetIdentifier;
|
||||||
|
|
||||||
|
public this(AssetIdentifier ownAssetIdentifier)
|
||||||
|
{
|
||||||
|
_assetIdentifier = ownAssetIdentifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ImportedTexture : ImportedResource
|
||||||
|
{
|
||||||
|
//public TextureDimension TextureType;
|
||||||
|
private List<LoadedSurface> _surfaces = new .() ~ delete _;
|
||||||
|
private LoadedTextureInfo _textureInfo ~ delete _textureInfo.PixelData;
|
||||||
|
|
||||||
|
public List<LoadedSurface> Surfaces => _surfaces;
|
||||||
|
|
||||||
|
public ref LoadedTextureInfo TextureInfo => ref _textureInfo;
|
||||||
|
|
||||||
|
public this(AssetIdentifier ownAssetIdentifier) : base(ownAssetIdentifier)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
class TextureImporterConfig : AssetImporterConfig
|
||||||
|
{
|
||||||
|
[BonInclude]
|
||||||
|
private bool _isSrgb;
|
||||||
|
|
||||||
|
public bool IsSrgb
|
||||||
|
{
|
||||||
|
get => _isSrgb;
|
||||||
|
set => SetIfChanged(ref _isSrgb, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class TextureImporter : IAssetImporter
|
||||||
|
{
|
||||||
|
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _;
|
||||||
|
|
||||||
|
public static List<StringView> FileExtensions => _fileExtensions;
|
||||||
|
|
||||||
|
public AssetImporterConfig CreateDefaultConfig()
|
||||||
|
{
|
||||||
|
return new TextureImporterConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<ImportedResource> Import(StringView fullFileName, AssetIdentifier assetIdentifier, AssetImporterConfig config)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug(config is TextureImporterConfig);
|
||||||
|
|
||||||
|
ImportedTexture importedData = new ImportedTexture(new AssetIdentifier(assetIdentifier.FullIdentifier));
|
||||||
|
|
||||||
|
// TODO: Get stream from asset mananger?
|
||||||
|
FileStream stream = scope FileStream();
|
||||||
|
Try!(stream.Open(fullFileName, .Read, .Read));
|
||||||
|
|
||||||
|
Result<void> importResult = ImportTexture(stream, importedData, (TextureImporterConfig)config);
|
||||||
|
|
||||||
|
stream.Close();
|
||||||
|
|
||||||
|
if (importResult case .Err)
|
||||||
|
{
|
||||||
|
delete importedData;
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return importedData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
||||||
|
const String DdsMagicWord = "DDS ";
|
||||||
|
|
||||||
|
enum TextureType
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
DDS,
|
||||||
|
PNG
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureType GetTextureType(Stream data)
|
||||||
|
{
|
||||||
|
int64 position = data.Position;
|
||||||
|
|
||||||
|
var readResult = data.Read<char8[8]>();
|
||||||
|
|
||||||
|
data.Position = position;
|
||||||
|
|
||||||
|
char8[8] magicWord;
|
||||||
|
if (readResult case .Ok(out magicWord))
|
||||||
|
{
|
||||||
|
StringView strView = .(&magicWord, magicWord.Count);
|
||||||
|
|
||||||
|
if (strView.StartsWith(PngMagicWord))
|
||||||
|
{
|
||||||
|
return .PNG;
|
||||||
|
}
|
||||||
|
else if (strView.StartsWith(DdsMagicWord))
|
||||||
|
{
|
||||||
|
return .DDS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Runtime.FatalError("Unknown image format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void> ImportTexture(Stream data, ImportedTexture importedTexture, TextureImporterConfig config)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
switch(GetTextureType(data))
|
||||||
|
{
|
||||||
|
case .DDS:
|
||||||
|
Try!(LoadDds(data, config, importedTexture.Surfaces, out importedTexture.TextureInfo));
|
||||||
|
case .PNG:
|
||||||
|
Try!(LoadPng(data, config, importedTexture.Surfaces, out importedTexture.TextureInfo));
|
||||||
|
case .Unknown:
|
||||||
|
Log.EngineLogger.Error("Unknown texture format.");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void> LoadPng(Stream data, TextureImporterConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
textureInfo = .();
|
||||||
|
|
||||||
|
uint8[] pngData = new:ScopedAlloc! uint8[data.Length];
|
||||||
|
|
||||||
|
var result = data.TryRead(pngData);
|
||||||
|
|
||||||
|
if (result case .Err(let err))
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* rawData = null;
|
||||||
|
defer
|
||||||
|
{
|
||||||
|
if (rawData != null)
|
||||||
|
LodePng.LodePng.Free(rawData);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 width = 0, height = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceScope!("LodePng.LodePng.Decode32");
|
||||||
|
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
||||||
|
if (errorCode != 0)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.Error($"Failed to decode PNG file {errorCode}.");
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8[] pixelData = new uint8[4 * width * height];
|
||||||
|
Internal.MemCpy(pixelData.Ptr, rawData, pixelData.Count);
|
||||||
|
|
||||||
|
LoadedSurface surface = .();
|
||||||
|
surface.Data = Span<uint8>(pixelData);
|
||||||
|
surface.Pitch = 4 * width;
|
||||||
|
surface.SlicePitch = 0;
|
||||||
|
surface.ArrayIndex = 0;
|
||||||
|
surface.MipLevel = 0;
|
||||||
|
|
||||||
|
surfaces.Add(surface);
|
||||||
|
|
||||||
|
textureInfo.PixelData = pixelData;
|
||||||
|
textureInfo.Width = width;
|
||||||
|
textureInfo.Height = height;
|
||||||
|
textureInfo.Depth = 1;
|
||||||
|
|
||||||
|
textureInfo.ArraySize = 1;
|
||||||
|
textureInfo.MipMapCount = 1;
|
||||||
|
|
||||||
|
textureInfo.Dimension = .Texture2D;
|
||||||
|
|
||||||
|
textureInfo.IsCubeMap = false;
|
||||||
|
|
||||||
|
// TODO: PNG supports multiple colordepths! (Grayscale up to 16 bit, RGB 8 or 16 bit)
|
||||||
|
textureInfo.PixelFormat = config.IsSrgb ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Result<void> LoadDds(Stream data, TextureImporterConfig config, List<LoadedSurface> surfaces, out LoadedTextureInfo textureInfo)
|
||||||
|
{
|
||||||
|
var result = DdsImporter.LoadDds(data, config.IsSrgb, surfaces, out textureInfo);
|
||||||
|
|
||||||
|
if (result case .Err)
|
||||||
|
return .Err;
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum GenerateMipMaps
|
||||||
|
{
|
||||||
|
No,
|
||||||
|
Box,
|
||||||
|
Kaiser
|
||||||
|
}
|
||||||
|
|
||||||
|
[BonTarget, BonPolyRegister]
|
||||||
|
class TextureProcessorConfig : AssetProcessorConfig
|
||||||
|
{
|
||||||
|
[BonInclude]
|
||||||
|
private GenerateMipMaps _generateMipMaps;
|
||||||
|
|
||||||
|
public GenerateMipMaps GenerateMipMaps
|
||||||
|
{
|
||||||
|
get => _generateMipMaps;
|
||||||
|
set => SetIfChanged(ref _generateMipMaps, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProcessedResource
|
||||||
|
{
|
||||||
|
private AssetIdentifier _assetIdentifier ~ delete _;
|
||||||
|
|
||||||
|
public AssetIdentifier AssetIdentifier => _assetIdentifier;
|
||||||
|
|
||||||
|
public this(AssetIdentifier ownAssetIdentifier)
|
||||||
|
{
|
||||||
|
_assetIdentifier = ownAssetIdentifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ProcessedTexture : ProcessedResource
|
||||||
|
{
|
||||||
|
public Format PixelFormat = .Unknown;
|
||||||
|
public int MipMapCount = -1;
|
||||||
|
public int ArraySize = -1;
|
||||||
|
public Dimension Dimension = .Unknown;
|
||||||
|
public bool IsCubeMap;
|
||||||
|
|
||||||
|
public int Width = -1;
|
||||||
|
public int Height = -1;
|
||||||
|
public int Depth = -1;
|
||||||
|
|
||||||
|
public class TextureSurface
|
||||||
|
{
|
||||||
|
public uint8[] PixelData;
|
||||||
|
public int Width;
|
||||||
|
public int Height;
|
||||||
|
public int Depth;
|
||||||
|
public int MipLevel;
|
||||||
|
public int ArraySlice;
|
||||||
|
|
||||||
|
[AllowAppend]
|
||||||
|
public this(int width, int height, int depth, Span<uint8> data, int mipLevel, int arraySlice)
|
||||||
|
{
|
||||||
|
uint8[] pixelData = append uint8[data.Length];
|
||||||
|
data.CopyTo(pixelData);
|
||||||
|
|
||||||
|
PixelData = pixelData;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
Depth = depth;
|
||||||
|
MipLevel = mipLevel;
|
||||||
|
ArraySlice = arraySlice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint64 LoadRaw(int x, int y, int z, Format format, ComponentInfo component)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug(x >= 0 && y >= 0 && z >= 0 && x < Width && y < Height && z < Depth);
|
||||||
|
|
||||||
|
int64 pixelOffset = x + (Width * y) + (Width * Height) * z;
|
||||||
|
|
||||||
|
int64 bitOffset = pixelOffset * format.BitsPerPixel();
|
||||||
|
|
||||||
|
bitOffset += component.BitSize;
|
||||||
|
|
||||||
|
int64 byteOffset = bitOffset / 8;
|
||||||
|
int shift = bitOffset % 8;
|
||||||
|
|
||||||
|
int bytesToRead = (component.BitSize + shift) / 8;
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(bytesToRead <= 8);
|
||||||
|
|
||||||
|
uint64 data = 0;
|
||||||
|
|
||||||
|
data = PixelData.Ptr[byteOffset];
|
||||||
|
data >>= shift;
|
||||||
|
uint64 mask = (1 << component.BitSize) - 1;
|
||||||
|
data &= mask;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureSurface[,] Surfaces;
|
||||||
|
|
||||||
|
public this(AssetIdentifier ownAssetIdentifier) : base(ownAssetIdentifier)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ~this()
|
||||||
|
{
|
||||||
|
for (int i < Surfaces?.GetLength(0) ?? 0)
|
||||||
|
{
|
||||||
|
for (int j < Surfaces.GetLength(1))
|
||||||
|
{
|
||||||
|
delete Surfaces[i, j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete Surfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSurfaceCount(int arraySize, int mipMapCount)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug(arraySize > Surfaces.GetLength(0));
|
||||||
|
Log.EngineLogger.AssertDebug(mipMapCount > Surfaces.GetLength(1));
|
||||||
|
|
||||||
|
TextureSurface[,] oldSurfaces = Surfaces;
|
||||||
|
Surfaces = new TextureSurface[arraySize, mipMapCount];
|
||||||
|
|
||||||
|
for (int i < oldSurfaces.GetLength(0))
|
||||||
|
{
|
||||||
|
for (int j < oldSurfaces.GetLength(1))
|
||||||
|
{
|
||||||
|
Surfaces[i, j] = oldSurfaces[i, j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextureProcessor : IAssetProcessor
|
||||||
|
{
|
||||||
|
public AssetProcessorConfig CreateDefaultConfig()
|
||||||
|
{
|
||||||
|
return new TextureProcessorConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<Object> 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<void> ProcessTexture(ImportedTexture importedTexture, TextureProcessorConfig config)
|
||||||
|
{
|
||||||
|
ProcessedTexture processedTexture = new ProcessedTexture(new AssetIdentifier(importedTexture.AssetIdentifier.FullIdentifier));
|
||||||
|
|
||||||
|
processedTexture.SetSurfaceCount(importedTexture.TextureInfo.ArraySize, importedTexture.TextureInfo.MipMapCount);
|
||||||
|
|
||||||
|
for (LoadedSurface loadedSurface in importedTexture.Surfaces)
|
||||||
|
{
|
||||||
|
ProcessedTexture.TextureSurface surface = new .(loadedSurface.Width, loadedSurface.Height, loadedSurface.Depth,
|
||||||
|
loadedSurface.Data, loadedSurface.MipLevel, loadedSurface.ArrayIndex);
|
||||||
|
processedTexture.Surfaces[loadedSurface.ArrayIndex, loadedSurface.MipLevel] = surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(config.GenerateMipMaps case .No))
|
||||||
|
{
|
||||||
|
// TODO: Unpack BC-Formats to RGBA
|
||||||
|
|
||||||
|
GenerateMipMaps(processedTexture, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Pack to BC-Format or what ever was selected.
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CalculateMipMapCount(int width, int height, int depth)
|
||||||
|
{
|
||||||
|
var width, height, depth;
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (width == 1 && height == 1 && depth == 1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (width > 1)
|
||||||
|
width >>= 1;
|
||||||
|
if (height > 1)
|
||||||
|
height >>= 1;
|
||||||
|
if (depth > 1)
|
||||||
|
depth >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanGenerateMipMaps(Format format)
|
||||||
|
{
|
||||||
|
// TODO!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Result<void> GenerateMipMaps(ProcessedTexture processedTexture, TextureProcessorConfig config)
|
||||||
|
{
|
||||||
|
if (!CanGenerateMipMaps(processedTexture.PixelFormat))
|
||||||
|
{
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mipMapCount = CalculateMipMapCount(processedTexture.Width, processedTexture.Height, processedTexture.Depth);
|
||||||
|
|
||||||
|
if (processedTexture.MipMapCount != mipMapCount)
|
||||||
|
{
|
||||||
|
processedTexture.SetSurfaceCount(processedTexture.ArraySize, mipMapCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int arraySlice < processedTexture.ArraySize)
|
||||||
|
{
|
||||||
|
ProcessedTexture.TextureSurface largerSurface = processedTexture.Surfaces[arraySlice, 0];
|
||||||
|
|
||||||
|
for (int mipMap = 1; mipMap < processedTexture.MipMapCount; mipMap++)
|
||||||
|
{
|
||||||
|
ref ProcessedTexture.TextureSurface surface = ref processedTexture.Surfaces[arraySlice, mipMap];
|
||||||
|
|
||||||
|
surface = GenerateMipLevel(processedTexture.PixelFormat, largerSurface, surface);
|
||||||
|
|
||||||
|
largerSurface = surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
|
||||||
|
// TODO: Generate Mip Maps
|
||||||
|
/*int mipMapCount = CalculateMipMapCount(processedTexture.Width, processedTexture.Height, processedTexture.Depth);
|
||||||
|
|
||||||
|
processedTexture.SetMipMapCount(mipMapCount);
|
||||||
|
|
||||||
|
for (int slice < processedTexture.ArraySize)
|
||||||
|
{
|
||||||
|
for (int mipMap < mipMapCount)
|
||||||
|
{
|
||||||
|
if (processedTexture.Surfaces[slice, mipMap] == null)
|
||||||
|
{
|
||||||
|
processedTexture.Surfaces[slice, mipMap] = GenerateMipLevel(processedTexture.Surfaces[slice, mipMap - 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessedTexture.TextureSurface GenerateMipLevel(Format pixelFormat, ProcessedTexture.TextureSurface largerLevel, ProcessedTexture.TextureSurface smallerLevel)
|
||||||
|
{
|
||||||
|
var smallerLevel;
|
||||||
|
|
||||||
|
int width = Math.Max(largerLevel.Width / 2, 1);
|
||||||
|
int height = Math.Max(largerLevel.Height / 2, 1);
|
||||||
|
int depth = Math.Max(largerLevel.Depth / 2, 1);
|
||||||
|
|
||||||
|
if (smallerLevel == null)
|
||||||
|
{
|
||||||
|
smallerLevel = new ProcessedTexture.TextureSurface(width, height, depth, new uint8[width * height * depth * pixelFormat.BitsPerPixel()], largerLevel.MipLevel + 1, largerLevel.ArraySlice);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Kaiser mip maps?
|
||||||
|
|
||||||
|
FormatInfo formatInfo = default; //pixelFormat.GetFormatInfo();
|
||||||
|
|
||||||
|
// Simple box filter
|
||||||
|
for (int x < width)
|
||||||
|
for (int y < height)
|
||||||
|
for (int z < depth)
|
||||||
|
{
|
||||||
|
for (int channel < formatInfo.ComponentCount)
|
||||||
|
{
|
||||||
|
ComponentInfo info = formatInfo.Components[channel];
|
||||||
|
|
||||||
|
switch (info.DataType)
|
||||||
|
{
|
||||||
|
case .UNorm, .UInt:
|
||||||
|
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return smallerLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Box<DataType>() where DataType : const ComponentDataType
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextureExporter : IAssetExporter
|
||||||
|
{
|
||||||
|
public AssetExporterConfig CreateDefaultConfig()
|
||||||
|
{
|
||||||
|
return new AssetExporterConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Result<void> Export(Stream stream, ProcessedResource processedResource, AssetExporterConfig config)
|
||||||
|
{
|
||||||
|
Log.EngineLogger.AssertDebug(processedResource is ProcessedTexture);
|
||||||
|
|
||||||
|
ProcessedTexture processedTexture = (.)processedResource;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
File Format:
|
||||||
|
TextureType (1 byte)
|
||||||
|
Pixel Format (4 bytes)
|
||||||
|
Width of larges mip-slice (4 bytes)
|
||||||
|
Height of larges mip-slice (4 bytes)
|
||||||
|
Depth of larges mip-slice (4 bytes)
|
||||||
|
Array size (4 bytes)
|
||||||
|
Mip map levels (4 bytes)
|
||||||
|
Pixeldata
|
||||||
|
{
|
||||||
|
Array[0]: Mip[0] Mip[1] ... Mip[M]
|
||||||
|
Array[1]: Mip[0] Mip[1] ... Mip[M]
|
||||||
|
...
|
||||||
|
Array[N]: Mip[0] Mip[1] ... Mip[M]
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
Try!(stream.Write(processedTexture.Dimension));
|
||||||
|
Try!(stream.Write(processedTexture.PixelFormat));
|
||||||
|
Try!(stream.Write((uint32)processedTexture.Width));
|
||||||
|
Try!(stream.Write((uint32)processedTexture.Height));
|
||||||
|
Try!(stream.Write((uint32)processedTexture.Depth));
|
||||||
|
Try!(stream.Write((uint32)processedTexture.ArraySize));
|
||||||
|
Try!(stream.Write((uint32)processedTexture.MipMapCount));
|
||||||
|
|
||||||
|
for (int arraySlice < processedTexture.ArraySize)
|
||||||
|
{
|
||||||
|
int validateWidth = processedTexture.Width;
|
||||||
|
int validateHeight = processedTexture.Height;
|
||||||
|
int validateDepth = processedTexture.Depth;
|
||||||
|
|
||||||
|
for (int mipSlice < processedTexture.MipMapCount)
|
||||||
|
{
|
||||||
|
ProcessedTexture.TextureSurface slice = processedTexture.Surfaces[arraySlice, mipSlice];
|
||||||
|
|
||||||
|
Log.EngineLogger.AssertDebug(validateWidth == slice.Width);
|
||||||
|
Log.EngineLogger.AssertDebug(validateHeight == slice.Height);
|
||||||
|
Log.EngineLogger.AssertDebug(validateDepth == slice.Depth);
|
||||||
|
validateWidth /= 2;
|
||||||
|
validateHeight /= 2;
|
||||||
|
validateDepth /= 2;
|
||||||
|
|
||||||
|
if (validateWidth < 1)
|
||||||
|
validateWidth = 1;
|
||||||
|
|
||||||
|
if (validateHeight < 1)
|
||||||
|
validateHeight = 1;
|
||||||
|
|
||||||
|
if (validateDepth < 1)
|
||||||
|
validateDepth = 1;
|
||||||
|
|
||||||
|
Try!(stream.TryWrite(slice.PixelData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return .Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TextureLoader
|
||||||
|
{
|
||||||
|
public Result<Asset> Load(Stream data, AssetIdentifier assetIdentifier)
|
||||||
|
{
|
||||||
|
Dimension dimension = Try!(data.Read<Dimension>());
|
||||||
|
Format pixelFormat = Try!(data.Read<Format>());
|
||||||
|
uint32 width = Try!(data.Read<uint32>());
|
||||||
|
uint32 height = Try!(data.Read<uint32>());
|
||||||
|
uint32 depth = Try!(data.Read<uint32>());
|
||||||
|
uint32 arraySize = Try!(data.Read<uint32>());
|
||||||
|
uint32 mipMapCount = Try!(data.Read<uint32>());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return .Ok(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -343,7 +343,7 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
|||||||
staging.MipLevels = (.)textureInfo.MipMapCount;
|
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||||
staging.ArraySize = (.)textureInfo.ArraySize;
|
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||||
|
|
||||||
staging.Format = textureInfo.PixelFormat;
|
staging.Format = (.)textureInfo.PixelFormat;
|
||||||
|
|
||||||
// TODO: allow enabling read/write
|
// TODO: allow enabling read/write
|
||||||
staging.CpuAccess = .None;
|
staging.CpuAccess = .None;
|
||||||
@@ -370,7 +370,7 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
|||||||
staging.MipLevels = (.)textureInfo.MipMapCount;
|
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||||
staging.ArraySize = (.)textureInfo.ArraySize;
|
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||||
|
|
||||||
staging.Format = textureInfo.PixelFormat;
|
staging.Format = (.)textureInfo.PixelFormat;
|
||||||
|
|
||||||
// TODO: allow enabling read/write
|
// TODO: allow enabling read/write
|
||||||
staging.CpuAccess = .None;
|
staging.CpuAccess = .None;
|
||||||
|
|||||||
@@ -561,7 +561,7 @@ class TexturererViewerer
|
|||||||
|
|
||||||
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
|
_renderTargetEffect.Variables["Swizzle"].SetData(int4((int32)_swizzleR, (int32)_swizzleG, (int32)_swizzleB, (int32)_swizzleA));
|
||||||
|
|
||||||
if (format.IsInt())
|
if (((DirectX.DXGI.Format)format).IsInt())
|
||||||
{
|
{
|
||||||
// Int Texture
|
// Int Texture
|
||||||
_renderTargetEffect.Variables["Mode"].SetData(1);
|
_renderTargetEffect.Variables["Mode"].SetData(1);
|
||||||
@@ -598,7 +598,7 @@ class TexturererViewerer
|
|||||||
{
|
{
|
||||||
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
|
var desc = _groupIndex >= 0 ? viewedTexture.[Friend]_colorTargetDescriptions[_groupIndex] : viewedTexture.[Friend]_depthTargetDescription;
|
||||||
|
|
||||||
RenderTexture(viewedTexture.GetViewBinding(_groupIndex), float2(viewedTexture.Width, viewedTexture.Height), desc.Format.GetShaderViewFormat());
|
RenderTexture(viewedTexture.GetViewBinding(_groupIndex), float2(viewedTexture.Width, viewedTexture.Height), (.)desc.Format.GetShaderViewFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderTexture(Texture viewedTexture)
|
private void RenderTexture(Texture viewedTexture)
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ class PropertiesWindow : EditorWindow
|
|||||||
Asset asset = _editor.ContentManager.GetAsset(null, _currentAssetHandle);
|
Asset asset = _editor.ContentManager.GetAsset(null, _currentAssetHandle);
|
||||||
|
|
||||||
// We need the actual asset for preview and sometimes for editing
|
// We need the actual asset for preview and sometimes for editing
|
||||||
if (asset?.Identifier != assetFile.Identifier)
|
if (asset?.Identifier != assetFile.AssetFile.Identifier)
|
||||||
{
|
{
|
||||||
_currentAssetHandle = _editor.ContentManager.LoadAsset(assetFile.Identifier);
|
_currentAssetHandle = _editor.ContentManager.LoadAsset(assetFile.AssetFile.Identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: allow changing AssetLoader
|
// TODO: allow changing AssetLoader
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ using System;
|
|||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
using GlitchyEngine.Content;
|
using GlitchyEngine.Content;
|
||||||
using GlitchyEditor.Assets;
|
using GlitchyEditor.Assets;
|
||||||
|
using GlitchyEditor.Assets.Importers;
|
||||||
|
|
||||||
namespace GlitchyEditor
|
namespace GlitchyEditor
|
||||||
{
|
{
|
||||||
@@ -36,6 +37,12 @@ namespace GlitchyEditor
|
|||||||
_contentManager.SetAsDefaultAssetLoader<EffectAssetLoader>(".hlsl");
|
_contentManager.SetAsDefaultAssetLoader<EffectAssetLoader>(".hlsl");
|
||||||
_contentManager.SetAssetPropertiesEditor<EffectAssetLoader>(=> EffectAssetPropertiesEditor.Factory);
|
_contentManager.SetAssetPropertiesEditor<EffectAssetLoader>(=> EffectAssetPropertiesEditor.Factory);
|
||||||
|
|
||||||
|
_contentManager.RegisterAssetImporter<TextureImporter>();
|
||||||
|
_contentManager.RegisterAssetProcessor<TextureProcessor>();
|
||||||
|
_contentManager.RegisterAssetExporter<TextureExporter>();
|
||||||
|
|
||||||
|
_contentManager.ConfigureDefaultProcessing<TextureImporter, TextureProcessor, TextureExporter>(".png");
|
||||||
|
|
||||||
_contentManager.SetResourcesDirectory("./Resources");
|
_contentManager.SetResourcesDirectory("./Resources");
|
||||||
|
|
||||||
return _contentManager;
|
return _contentManager;
|
||||||
|
|||||||
@@ -9,6 +9,9 @@ using GlitchyEditor.Assets;
|
|||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using GlitchyEditor.Assets.Importers;
|
||||||
|
using GlitchyEngine.Core;
|
||||||
|
|
||||||
using internal GlitchyEngine.Content.Asset;
|
using internal GlitchyEngine.Content.Asset;
|
||||||
|
|
||||||
namespace GlitchyEditor;
|
namespace GlitchyEditor;
|
||||||
@@ -17,19 +20,22 @@ class EditorContentManager : IContentManager
|
|||||||
{
|
{
|
||||||
private append String _resourcesDirectory = .();
|
private append String _resourcesDirectory = .();
|
||||||
private append String _assetsDirectory = .();
|
private append String _assetsDirectory = .();
|
||||||
|
|
||||||
public StringView ResourcesDirectory => _resourcesDirectory;
|
|
||||||
public StringView AssetDirectory => _assetsDirectory;
|
|
||||||
|
|
||||||
private append Dictionary<StringView, AssetHandle> _identiferToHandle = .(); // TODO: Check if all resources are unloaded
|
private append Dictionary<StringView, AssetHandle> _identiferToHandle = .(); // TODO: Check if all resources are unloaded
|
||||||
|
|
||||||
private append Dictionary<AssetHandle, Asset> _handleToAsset = .();
|
private append Dictionary<AssetHandle, Asset> _handleToAsset = .();
|
||||||
|
|
||||||
private append AssetHierarchy _assetHierarchy = .(this);
|
private append AssetHierarchy _assetHierarchy = .(this);
|
||||||
|
private append AssetCache _assetCache = .() ~ delete:append _;
|
||||||
public AssetHierarchy AssetHierarchy => _assetHierarchy;
|
private append AssetConverter _assetConverter = .(this) ~ delete:append _;
|
||||||
|
|
||||||
private append List<AssetHandle> _reloadQueue = .();
|
private append List<AssetHandle> _reloadQueue = .();
|
||||||
|
|
||||||
|
public StringView ResourcesDirectory => _resourcesDirectory;
|
||||||
|
public StringView AssetDirectory => _assetsDirectory;
|
||||||
|
public AssetHierarchy AssetHierarchy => _assetHierarchy;
|
||||||
|
public AssetCache AssetCache => _assetCache;
|
||||||
|
public AssetConverter AssetConverter => _assetConverter;
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
@@ -45,7 +51,7 @@ class EditorContentManager : IContentManager
|
|||||||
private void OnFileContentChanged(AssetNode assetNode)
|
private void OnFileContentChanged(AssetNode assetNode)
|
||||||
{
|
{
|
||||||
// Asset isn't loaded so we don't need to reload it.
|
// Asset isn't loaded so we don't need to reload it.
|
||||||
if (assetNode.AssetFile.LoadedAsset == null)
|
if (assetNode.AssetFile?.LoadedAsset == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_reloadQueue.Add(assetNode.AssetFile.LoadedAsset.Handle);
|
_reloadQueue.Add(assetNode.AssetFile.LoadedAsset.Handle);
|
||||||
@@ -60,7 +66,7 @@ class EditorContentManager : IContentManager
|
|||||||
Asset asset = assetNode.AssetFile.LoadedAsset;
|
Asset asset = assetNode.AssetFile.LoadedAsset;
|
||||||
|
|
||||||
_identiferToHandle.Remove(oldIdentifier);
|
_identiferToHandle.Remove(oldIdentifier);
|
||||||
asset.Identifier = assetNode.AssetFile.Identifier;
|
asset.Identifier = assetNode.Identifier;
|
||||||
_identiferToHandle.Add(asset.Identifier, asset.Handle);
|
_identiferToHandle.Add(asset.Identifier, asset.Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,8 +86,15 @@ class EditorContentManager : IContentManager
|
|||||||
_assetHierarchy.SetAssetsDirectory(_assetsDirectory);
|
_assetHierarchy.SetAssetsDirectory(_assetsDirectory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetAssetCacheDirectory(StringView fileName)
|
||||||
|
{
|
||||||
|
_assetCache.SetDirectory(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
_assetConverter.Update();
|
||||||
|
|
||||||
SwapInLoadedAssets();
|
SwapInLoadedAssets();
|
||||||
|
|
||||||
if (!_reloadQueue.IsEmpty)
|
if (!_reloadQueue.IsEmpty)
|
||||||
@@ -135,6 +148,16 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: This type sucks!
|
||||||
|
public Result<(IAssetImporter Importer, IAssetProcessor Processor, IAssetExporter Exporter)> GetDefaultProcessors(StringView fileExtension)
|
||||||
|
{
|
||||||
|
if (_defaultAssetProcessors.TryGetValue(fileExtension, let value))
|
||||||
|
return value;
|
||||||
|
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
private append List<String> _supportedExtensions = .() ~ ClearAndDeleteItems!(_);
|
private append List<String> _supportedExtensions = .() ~ ClearAndDeleteItems!(_);
|
||||||
private append List<IAssetLoader> _assetLoaders = .() ~ ClearAndDeleteItems!(_);
|
private append List<IAssetLoader> _assetLoaders = .() ~ ClearAndDeleteItems!(_);
|
||||||
private append Dictionary<StringView, IAssetLoader> _defaultAssetLoaders = .();
|
private append Dictionary<StringView, IAssetLoader> _defaultAssetLoaders = .();
|
||||||
@@ -143,8 +166,14 @@ class EditorContentManager : IContentManager
|
|||||||
{
|
{
|
||||||
delete key;
|
delete key;
|
||||||
}
|
}
|
||||||
|
delete:append _;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private append List<IAssetImporter> _assetImporters = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private append List<IAssetProcessor> _assetProcessors = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private append List<IAssetExporter> _assetExporters = .() ~ ClearAndDeleteItems!(_);
|
||||||
|
private append Dictionary<StringView, (IAssetImporter Importer, IAssetProcessor Processor, IAssetExporter Exporter)> _defaultAssetProcessors = .() ~ delete:append _;
|
||||||
|
|
||||||
public void RegisterAssetLoader<T>() where T : new, class, IAssetLoader
|
public void RegisterAssetLoader<T>() where T : new, class, IAssetLoader
|
||||||
{
|
{
|
||||||
// Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered.");
|
// Log.EngineLogger.AssertDebug(!_assetLoaders.Any((l) => l.GetType() == typeof(T)), "Asset loader already registered.");
|
||||||
@@ -157,6 +186,30 @@ class EditorContentManager : IContentManager
|
|||||||
_supportedExtensions.Add(new String(ext));
|
_supportedExtensions.Add(new String(ext));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterAssetImporter<T>() where T : new, class, IAssetImporter
|
||||||
|
{
|
||||||
|
T assetImporter = new T();
|
||||||
|
|
||||||
|
_assetImporters.Add(assetImporter);
|
||||||
|
|
||||||
|
for (StringView ext in T.FileExtensions)
|
||||||
|
_supportedExtensions.Add(new String(ext));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterAssetProcessor<T>() where T : new, class, IAssetProcessor
|
||||||
|
{
|
||||||
|
T assetProcessor = new T();
|
||||||
|
|
||||||
|
_assetProcessors.Add(assetProcessor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterAssetExporter<T>() where T : new, class, IAssetExporter
|
||||||
|
{
|
||||||
|
T assetExporter = new T();
|
||||||
|
|
||||||
|
_assetExporters.Add(assetExporter);
|
||||||
|
}
|
||||||
|
|
||||||
public void SetAsDefaultAssetLoader<T>(params Span<StringView> fileExtensions) where T : IAssetLoader
|
public void SetAsDefaultAssetLoader<T>(params Span<StringView> fileExtensions) where T : IAssetLoader
|
||||||
{
|
{
|
||||||
for (var ext in fileExtensions)
|
for (var ext in fileExtensions)
|
||||||
@@ -185,6 +238,63 @@ class EditorContentManager : IContentManager
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void ConfigureDefaultProcessing<TImport, TProcess, TExport>(params Span<StringView> fileExtensions) where TImport : IAssetImporter where TProcess : IAssetProcessor where TExport : IAssetExporter
|
||||||
|
{
|
||||||
|
for (var ext in fileExtensions)
|
||||||
|
{
|
||||||
|
// Find file extension in registered file extensions
|
||||||
|
String foundExtension = null;
|
||||||
|
|
||||||
|
for (var supportedExt in _supportedExtensions)
|
||||||
|
{
|
||||||
|
if (supportedExt == ext)
|
||||||
|
{
|
||||||
|
foundExtension = supportedExt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.EngineLogger.Assert(foundExtension != null, "File Extension is not registered.");
|
||||||
|
|
||||||
|
//IAssetImporter importer = _assetImporters.Where((i) => i.GetType() == typeof(TImport)).First();
|
||||||
|
//IAssetProcessor processor = _assetProcessors.Where((i) => i.GetType() == typeof(TProcess)).First();
|
||||||
|
//IAssetExporter exporter = _assetExporters.Where((i) => i.GetType() == typeof(TExport)).First();
|
||||||
|
|
||||||
|
IAssetImporter importer = null;
|
||||||
|
IAssetProcessor processor = null;
|
||||||
|
IAssetExporter exporter = null;
|
||||||
|
|
||||||
|
for (var i in _assetImporters)
|
||||||
|
{
|
||||||
|
if (i.GetType() == typeof(TImport))
|
||||||
|
{
|
||||||
|
importer = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i in _assetProcessors)
|
||||||
|
{
|
||||||
|
if (i.GetType() == typeof(TProcess))
|
||||||
|
{
|
||||||
|
processor = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var i in _assetExporters)
|
||||||
|
{
|
||||||
|
if (i.GetType() == typeof(TExport))
|
||||||
|
{
|
||||||
|
exporter = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_defaultAssetProcessors[foundExtension] = (importer, processor, exporter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void SetAssetPropertiesEditor(Type assetLoaderType, function AssetPropertiesEditor(AssetFile) editorFactory)
|
public void SetAssetPropertiesEditor(Type assetLoaderType, function AssetPropertiesEditor(AssetFile) editorFactory)
|
||||||
{
|
{
|
||||||
@@ -275,11 +385,12 @@ class EditorContentManager : IContentManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssetFile file = resultNode->Value.AssetFile;
|
AssetNode assetNode = resultNode->Value;
|
||||||
|
AssetFile file = assetNode.AssetFile;
|
||||||
|
|
||||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||||
|
|
||||||
Stream stream = OpenStream(file.FilePath, true);
|
Stream stream = OpenStream(assetNode.Path, true);
|
||||||
|
|
||||||
// TODO: Add async loading!
|
// TODO: Add async loading!
|
||||||
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||||
@@ -361,13 +472,13 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
String filePath = scope String(resultNode->Value.Path);
|
String filePath = scope String(resultNode->Value.Path);
|
||||||
|
|
||||||
AssetFile file = resultNode->Value.AssetFile;
|
AssetNode assetNode = resultNode->Value;
|
||||||
|
AssetFile file = assetNode.AssetFile;
|
||||||
|
|
||||||
GetResourceAndSubassetName(file.Identifier, let resourceName, let subassetName);
|
GetResourceAndSubassetName(assetNode.Identifier, let resourceName, let subassetName);
|
||||||
|
|
||||||
IAssetLoader assetLoader = GetAssetLoader(file);
|
IAssetLoader assetLoader = GetAssetLoader(file);
|
||||||
|
|
||||||
// TODO: what are we supposed to do if we don't find a loader? Surely not crash...
|
|
||||||
//Log.EngineLogger.AssertDebug(assetLoader != null);
|
//Log.EngineLogger.AssertDebug(assetLoader != null);
|
||||||
if (assetLoader == null)
|
if (assetLoader == null)
|
||||||
{
|
{
|
||||||
@@ -407,7 +518,7 @@ class EditorContentManager : IContentManager
|
|||||||
loadedAsset = placeholder;
|
loadedAsset = placeholder;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedAsset.Identifier = file.Identifier;
|
loadedAsset.Identifier = assetNode.Identifier;
|
||||||
|
|
||||||
_handleToAsset.Add(handle, loadedAsset);
|
_handleToAsset.Add(handle, loadedAsset);
|
||||||
|
|
||||||
@@ -584,6 +695,26 @@ class EditorContentManager : IContentManager
|
|||||||
return assetLoader;
|
return assetLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IAssetImporter GetAssetImporter(AssetFile file)
|
||||||
|
{
|
||||||
|
IAssetImporter result = null;
|
||||||
|
|
||||||
|
String typeName = scope .(128);
|
||||||
|
|
||||||
|
for (IAssetImporter importer in _assetImporters)
|
||||||
|
{
|
||||||
|
importer.GetType().GetName(typeName..Clear());
|
||||||
|
|
||||||
|
if (typeName == file.AssetConfig.Importer)
|
||||||
|
{
|
||||||
|
result = importer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public enum SaveAssetError
|
public enum SaveAssetError
|
||||||
{
|
{
|
||||||
case Unknown;
|
case Unknown;
|
||||||
|
|||||||
@@ -765,6 +765,7 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
String appAssemblyPath = scope String();
|
String appAssemblyPath = scope String();
|
||||||
_contentManager.SetAssetDirectory(_currentProject.AssetsFolder);
|
_contentManager.SetAssetDirectory(_currentProject.AssetsFolder);
|
||||||
|
_contentManager.SetAssetCacheDirectory(_currentProject.GetScopedPath!(".cache"));
|
||||||
|
|
||||||
_currentProject.PathInProject(appAssemblyPath, scope $"bin/{_currentProject.Name}.dll");
|
_currentProject.PathInProject(appAssemblyPath, scope $"bin/{_currentProject.Name}.dll");
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GlitchyEngine.Content;
|
||||||
|
|
||||||
|
enum AssetCompression : uint8
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
L4Z
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace GlitchyEngine.Content;
|
||||||
|
|
||||||
|
enum AssetType : uint16
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Texture
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
public override uint32 Height => nativeDesc.Height;
|
public override uint32 Height => nativeDesc.Height;
|
||||||
public override uint32 ArraySize => nativeDesc.ArraySize;
|
public override uint32 ArraySize => nativeDesc.ArraySize;
|
||||||
public override uint32 MipLevels => nativeDesc.MipLevels;
|
public override uint32 MipLevels => nativeDesc.MipLevels;
|
||||||
public override Format Format => nativeDesc.Format;
|
public override Format Format => (.)nativeDesc.Format;
|
||||||
|
|
||||||
|
|
||||||
/*protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
/*protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
||||||
@@ -304,7 +304,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
public override uint32 Height => nativeDesc.Height;
|
public override uint32 Height => nativeDesc.Height;
|
||||||
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
|
public override uint32 ArraySize => nativeDesc.ArraySize / 6;
|
||||||
public override uint32 MipLevels => nativeDesc.MipLevels;
|
public override uint32 MipLevels => nativeDesc.MipLevels;
|
||||||
public override Format Format => nativeDesc.Format;
|
public override Format Format => (.)nativeDesc.Format;
|
||||||
|
|
||||||
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
protected override void CreateTexturePlatform(Texture2DDesc desc, bool isRenderTarget, void* data, uint32 linePitch)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
Debug.Assert(input.Count == output.Count);
|
Debug.Assert(input.Count == output.Count);
|
||||||
|
|
||||||
for(int i < input.Count)
|
for(int i < input.Count)
|
||||||
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass, input[i].InstanceDataStepRate);
|
output[i] = .(input[i].SemanticName, input[i].SemanticIndex, (.)input[i].Format, input[i].InputSlot, input[i].AlignedByteOffset, (.)input[i].InputSlotClass, input[i].InstanceDataStepRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates or gets the validated input layout for the given vertexshader.
|
/// Validates or gets the validated input layout for the given vertexshader.
|
||||||
|
|||||||
@@ -160,9 +160,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
//Structured = 2,
|
//Structured = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias Format = DirectX.DXGI.Format;
|
|
||||||
|
|
||||||
|
|
||||||
public struct BufferDescription
|
public struct BufferDescription
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user