mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Use asset pipeline for blocking asset loading, remove old texture loader
This commit is contained in:
@@ -10,3 +10,5 @@ GlitchyEditor/MonoDebugger.log
|
||||
|
||||
# Ignore files in build-directory of ScriptCore
|
||||
GlitchyEditor/Resources/Scripts/*
|
||||
|
||||
.cache
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
{
|
||||
AssetLoader = "EditorTextureAssetLoader",
|
||||
Config = (GlitchyEditor.Assets.EditorTextureAssetLoaderConfig){
|
||||
AssetLoader = null,
|
||||
Config = null,
|
||||
Importer = "TextureImporter",
|
||||
ImporterConfig = (GlitchyEditor.Assets.Importers.TextureImporterConfig){
|
||||
_isSrgb = false
|
||||
},
|
||||
Processor = "TextureProcessor",
|
||||
ProcessorConfig = (GlitchyEditor.Assets.Importers.TextureProcessorConfig){
|
||||
_generateMipMaps = .No,
|
||||
_samplerStateDescription = {
|
||||
MinFilter = .Linear,
|
||||
MagFilter = .Linear,
|
||||
MipFilter = .Linear,
|
||||
FilterMode = .Default,
|
||||
ComparisonFunction = .Never,
|
||||
AddressModeU = .Clamp,
|
||||
AddressModeV = .Clamp,
|
||||
AddressModeW = .Clamp,
|
||||
MipLODBias = 0,
|
||||
MipMinLOD = -3.40282347e+38,
|
||||
MipMaxLOD = 3.40282347e+38,
|
||||
MaxAnisotropy = 1,
|
||||
@@ -20,5 +29,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
AssetHandle = 16828117378770367285
|
||||
Exporter = "TextureExporter",
|
||||
ExporterConfig = {
|
||||
_compression = .LZ4
|
||||
},
|
||||
AssetHandle = 17972970543152031508
|
||||
}
|
||||
@@ -149,14 +149,17 @@ class AssetFile
|
||||
var assetLoader = _contentManager.GetDefaultAssetLoader(fileExtension);
|
||||
|
||||
// We don't have a loader -> we don't need a config
|
||||
if (assetLoader == null)
|
||||
if (assetLoader == null && assetPipeline case .Err)
|
||||
return;
|
||||
|
||||
if (assetLoader != null)
|
||||
{
|
||||
_assetConfig.AssetLoader = new String();
|
||||
assetLoader.GetType().GetName(_assetConfig.AssetLoader);
|
||||
|
||||
_assetConfig.Config = assetLoader?.GetDefaultConfig();
|
||||
_assetConfig.Config?.[Friend]_changed = true;
|
||||
}
|
||||
|
||||
_assetConfig.Importer = new String();
|
||||
assetPipeline?.Importer?.GetType()?.GetName(_assetConfig.Importer);
|
||||
|
||||
@@ -35,11 +35,13 @@ 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 String _projectCacheDirectory = .();// ~ delete:append _;
|
||||
private append String _globalCacheDirectory = .();// ~ delete:append _;
|
||||
|
||||
private append Dictionary<AssetHandle, CachedAsset> _assets = .();// ~ delete:append _;
|
||||
|
||||
public StringView CacheDirectory => _directory;
|
||||
public StringView ProjectCacheDirectory => _projectCacheDirectory;
|
||||
public StringView GlobalCacheDirectory => _globalCacheDirectory;
|
||||
|
||||
private bool _cacheLoaded;
|
||||
|
||||
@@ -62,9 +64,16 @@ class AssetCache
|
||||
}
|
||||
|
||||
/// Sets the directory in which the processed assets are cached.
|
||||
public void SetDirectory(StringView directory)
|
||||
public void SetGlobalCacheDirectory(StringView directory)
|
||||
{
|
||||
_directory.Set(directory);
|
||||
_globalCacheDirectory.Set(directory);
|
||||
ReloadCache();
|
||||
}
|
||||
|
||||
/// Sets the directory in which the processed assets are cached.
|
||||
public void SetProjectCacheDirectory(StringView directory)
|
||||
{
|
||||
_projectCacheDirectory.Set(directory);
|
||||
ReloadCache();
|
||||
}
|
||||
|
||||
@@ -73,13 +82,24 @@ class AssetCache
|
||||
{
|
||||
ClearCache();
|
||||
|
||||
if (!Directory.Exists(_directory))
|
||||
{
|
||||
Log.EngineLogger.Info($"Asset cache directory doesn't exist, creating directory \"{_directory}\"...");
|
||||
LoadCache(_globalCacheDirectory);
|
||||
LoadCache(_projectCacheDirectory);
|
||||
|
||||
if (Directory.CreateDirectory(_directory) case .Err(let error))
|
||||
_cacheLoaded = true;
|
||||
}
|
||||
|
||||
private void LoadCache(StringView directory)
|
||||
{
|
||||
Log.EngineLogger.Critical($"Failed to create cache directory \"{_directory}\". Reason: {error}.");
|
||||
if (directory.IsWhiteSpace)
|
||||
return;
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
@@ -89,7 +109,7 @@ class AssetCache
|
||||
}
|
||||
|
||||
String filePath = scope .();
|
||||
for (FileFindEntry file in Directory.EnumerateFiles(_directory))
|
||||
for (FileFindEntry file in Directory.EnumerateFiles(directory))
|
||||
{
|
||||
filePath.Clear();
|
||||
file.GetFilePath(filePath);
|
||||
@@ -108,8 +128,6 @@ class AssetCache
|
||||
|
||||
_assets.Add(cachedAsset.Handle, cachedAsset);
|
||||
}
|
||||
|
||||
_cacheLoaded = true;
|
||||
}
|
||||
|
||||
private Result<void> ReadAssetFile(StringView filePath, CachedAsset cachedAsset)
|
||||
@@ -170,9 +188,17 @@ class AssetCache
|
||||
return null;
|
||||
}
|
||||
|
||||
private void GetCacheFilePath(AssetHandle handle, String outFilePath)
|
||||
private void GetProjectCacheFilePath(AssetHandle handle, String outFilePath)
|
||||
{
|
||||
outFilePath.Append(_directory);
|
||||
outFilePath.Append(_projectCacheDirectory);
|
||||
outFilePath.Append(Path.DirectorySeparatorChar);
|
||||
outFilePath.Append(handle);
|
||||
outFilePath.Append(CachedAsset.CacheFileExtension);
|
||||
}
|
||||
|
||||
private void GetGlobalCacheFilePath(AssetHandle handle, String outFilePath)
|
||||
{
|
||||
outFilePath.Append(_globalCacheDirectory);
|
||||
outFilePath.Append(Path.DirectorySeparatorChar);
|
||||
outFilePath.Append(handle);
|
||||
outFilePath.Append(CachedAsset.CacheFileExtension);
|
||||
@@ -187,7 +213,12 @@ class AssetCache
|
||||
asset = new CachedAsset();
|
||||
asset.Handle = assetInfo.Handle;
|
||||
asset.FilePath = new String(128);
|
||||
GetCacheFilePath(asset.Handle, asset.FilePath);
|
||||
|
||||
if (assetInfo.AssetIdentifier.IsResource)
|
||||
GetGlobalCacheFilePath(asset.Handle, asset.FilePath);
|
||||
else
|
||||
GetProjectCacheFilePath(asset.Handle, asset.FilePath);
|
||||
|
||||
_assets[asset.Handle] = asset;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,12 @@ class AssetConverter
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public void QueueForProcessing(AssetFile assetFile)
|
||||
public void QueueForProcessing(AssetFile assetFile, bool isBlocking = false)
|
||||
{
|
||||
if (!isBlocking)
|
||||
_queue.Add(assetFile);
|
||||
else
|
||||
Process(assetFile);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
|
||||
@@ -375,12 +375,12 @@ class AssetHierarchy
|
||||
if (assetNode.IsInSubtree(_resourcesDirectoryNode))
|
||||
{
|
||||
Path.GetRelativePath(assetNode->Path, _resourcesDirectoryNode->Path, identifier);
|
||||
identifier.Insert(0, "Resources/");
|
||||
identifier.Insert(0, AssetIdentifier.ResourcesPrefix);
|
||||
}
|
||||
else if (assetNode.IsInSubtree(_assetsDirectoryNode))
|
||||
{
|
||||
Path.GetRelativePath(assetNode->Path, _assetsDirectoryNode->Path, identifier);
|
||||
identifier.Insert(0, "Assets/");
|
||||
identifier.Insert(0, AssetIdentifier.AssetsPrefix);
|
||||
}
|
||||
|
||||
delete assetNode->Identifier;
|
||||
|
||||
@@ -1,596 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Bon;
|
||||
using System.IO;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Content;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Math;
|
||||
using DirectXTK;
|
||||
using ImGui;
|
||||
using GlitchyEditor.Assets.Importers;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace GlitchyEditor.Assets;
|
||||
|
||||
class TextureAssetPropertiesEditor : AssetPropertiesEditor
|
||||
{
|
||||
EditorTextureAssetLoaderConfig _textureConfig;
|
||||
|
||||
public this(AssetFile asset) : base(asset)
|
||||
{
|
||||
_textureConfig = asset.AssetConfig.Config as EditorTextureAssetLoaderConfig;
|
||||
}
|
||||
|
||||
static char8*[3] _filterFuncNames = char8*[]("Point", "Linear", "Anisotropic");
|
||||
|
||||
public override void ShowEditor()
|
||||
{
|
||||
return;
|
||||
|
||||
if (_textureConfig == null)
|
||||
return;
|
||||
|
||||
bool generateMips = _textureConfig.GenerateMipMaps;
|
||||
if (ImGui.Checkbox("Generate Mip Maps", &generateMips))
|
||||
_textureConfig.GenerateMipMaps = generateMips;
|
||||
|
||||
bool isSrgb = _textureConfig.IsSRGB;
|
||||
if (ImGui.Checkbox("Is sRGB", &isSrgb))
|
||||
_textureConfig.IsSRGB = isSrgb;
|
||||
|
||||
SamplerStateDescription samplerStateDescription = _textureConfig.SamplerStateDescription;
|
||||
|
||||
void ShowFilterCombo(String label, ref FilterFunction filterFunction)
|
||||
{
|
||||
int32 selectedFilter = filterFunction.Underlying;
|
||||
if (ImGui.Combo(label, &selectedFilter, &_filterFuncNames, 3))
|
||||
filterFunction = (.)selectedFilter;
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Texture Filtering:");
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.EnumCombo("Min Filter", ref samplerStateDescription.MinFilter);
|
||||
ImGui.AttachTooltip("""
|
||||
Sampling method used for minification.
|
||||
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
|
||||
""");
|
||||
ImGui.EnumCombo("Mag Filter", ref samplerStateDescription.MagFilter);
|
||||
ImGui.AttachTooltip("""
|
||||
Sampling method used for magnification.
|
||||
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
|
||||
""");
|
||||
ImGui.EnumCombo("Mip Map Filter", ref samplerStateDescription.MipFilter);
|
||||
ImGui.AttachTooltip("""
|
||||
Method used for mip-level sampling.
|
||||
If set to "Anisotropic" all Filters are set to "Anisotropic" internally.
|
||||
""");
|
||||
|
||||
if (samplerStateDescription.MagFilter == .Anisotropic ||
|
||||
samplerStateDescription.MinFilter == .Anisotropic ||
|
||||
samplerStateDescription.MipFilter == .Anisotropic)
|
||||
{
|
||||
ImGui.SliderScalar("Anisotropy Level", ref samplerStateDescription.MaxAnisotropy, 1, 16);
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
|
||||
ImGui.EnumCombo("Filter Mode", ref samplerStateDescription.FilterMode);
|
||||
ImGui.AttachTooltip("Filtering method to use when sampling a texture.");
|
||||
|
||||
if (samplerStateDescription.FilterMode == .Comparison)
|
||||
{
|
||||
ImGui.EnumCombo("Comparison Function", ref samplerStateDescription.ComparisonFunction);
|
||||
ImGui.AttachTooltip("""
|
||||
The function that is used to compare the sampled data against the existing sampled data.
|
||||
Only applies if Filter Mode is set to FilterMode.Comparison.
|
||||
""");
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Wrapping");
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.EnumCombo("Wrap Mode U", ref samplerStateDescription.AddressModeU);
|
||||
ImGui.AttachTooltip("Method to use for resolving a u texture coordinate that is outside the 0 to 1 range.");
|
||||
|
||||
ImGui.EnumCombo("Wrap Mode V", ref samplerStateDescription.AddressModeV);
|
||||
ImGui.AttachTooltip("Method to use for resolving a v texture coordinate that is outside the 0 to 1 range.");
|
||||
|
||||
ImGui.EnumCombo("Wrap Mode W", ref samplerStateDescription.AddressModeW);
|
||||
ImGui.AttachTooltip("Method to use for resolving a w texture coordinate that is outside the 0 to 1 range.");
|
||||
|
||||
if (samplerStateDescription.AddressModeU == .Border ||
|
||||
samplerStateDescription.AddressModeV == .Border ||
|
||||
samplerStateDescription.AddressModeW == .Border)
|
||||
{
|
||||
ImGui.ColorEdit4("Border Color", ref samplerStateDescription.BorderColor);
|
||||
}
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Mip Maps");
|
||||
ImGui.Separator();
|
||||
|
||||
ImGui.DragFloat("Mip LOD Bias", &samplerStateDescription.MipLODBias, 0.1f);
|
||||
ImGui.AttachTooltip("""
|
||||
Offset from the calculated mipmap level.
|
||||
For example, if the GPU calculates that a texture should be sampled at mipmap level 3 and "Mip LOD Bias" is 2, then the texture will be sampled at mipmap level 5.
|
||||
""");
|
||||
|
||||
ImGui.DragFloat("Min Mip LOD", &samplerStateDescription.MipMinLOD);
|
||||
ImGui.AttachTooltip("Lower end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.");
|
||||
|
||||
ImGui.DragFloat("Max LOD Bias", &samplerStateDescription.MipMaxLOD);
|
||||
ImGui.AttachTooltip("""
|
||||
Upper end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.
|
||||
This value must be greater than or equal to "Min Mip LOD". To have no upper limit on LOD set this to a large value.
|
||||
""");
|
||||
|
||||
_textureConfig.SamplerStateDescription = samplerStateDescription;
|
||||
}
|
||||
|
||||
public static AssetPropertiesEditor Factory(AssetFile assetFile)
|
||||
{
|
||||
return new TextureAssetPropertiesEditor(assetFile);
|
||||
}
|
||||
}
|
||||
|
||||
[BonTarget, BonPolyRegister]
|
||||
class EditorTextureAssetLoaderConfig : AssetLoaderConfig
|
||||
{
|
||||
[BonInclude]
|
||||
private bool _generateMipMaps;
|
||||
|
||||
[BonInclude]
|
||||
private bool _isSrgb;
|
||||
|
||||
[BonInclude]
|
||||
private SamplerStateDescription _samplerStateDescription = .();
|
||||
|
||||
public bool GenerateMipMaps
|
||||
{
|
||||
get => _generateMipMaps;
|
||||
set => SetIfChanged(ref _generateMipMaps, value);
|
||||
}
|
||||
|
||||
public bool IsSRGB
|
||||
{
|
||||
get => _isSrgb;
|
||||
set => SetIfChanged(ref _isSrgb, value);
|
||||
}
|
||||
|
||||
public SamplerStateDescription SamplerStateDescription
|
||||
{
|
||||
get => _samplerStateDescription;
|
||||
set => SetIfChanged(ref _samplerStateDescription, value);
|
||||
}
|
||||
}
|
||||
|
||||
using internal GlitchyEngine.Renderer;
|
||||
using internal GlitchyEngine.Platform.DX11;
|
||||
|
||||
class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
||||
{
|
||||
private static readonly List<StringView> _fileExtensions = new .(){".png", ".dds"} ~ delete _; // ".jpg", ".bmp"
|
||||
|
||||
public static List<StringView> FileExtensions => _fileExtensions;
|
||||
|
||||
public AssetLoaderConfig GetDefaultConfig()
|
||||
{
|
||||
return new EditorTextureAssetLoaderConfig();
|
||||
}
|
||||
|
||||
public Asset LoadAsset(Stream data, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
|
||||
{
|
||||
var config;
|
||||
|
||||
if (config == null)
|
||||
{
|
||||
config = GetDefaultConfig();
|
||||
defer:: delete config;
|
||||
}
|
||||
|
||||
Log.EngineLogger.AssertDebug(config is EditorTextureAssetLoaderConfig, "config has wrong type.");
|
||||
|
||||
return LoadTexture(data, (EditorTextureAssetLoaderConfig)config);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/** \brief Loads the texture from the specified path.
|
||||
* @param path The path of the texture to load.
|
||||
* @param texture The reference to the pointer that will hold the texture.
|
||||
* @returns true if the texture was loaded successfully; false otherwise.
|
||||
*/
|
||||
protected static bool LoadDdsResourcePlatform(Stream stream)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
uint8[] ddsData = new:ScopedAlloc! uint8[stream.Length];
|
||||
|
||||
var result = stream.TryRead(ddsData);
|
||||
|
||||
if (result case .Err(let err))
|
||||
{
|
||||
Log.EngineLogger.Error($"Failed to read texture data from stream. Error: {err}");
|
||||
}
|
||||
|
||||
DirectX.D3D11.ID3D11Texture2D* texture = null;
|
||||
DirectX.D3D11.ID3D11ShaderResourceView* view = null;
|
||||
|
||||
DirectX.Common.HResult loadResult = DDSTextureLoader.CreateDDSTextureFromMemory(GlitchyEngine.Platform.DX11.NativeDevice,
|
||||
ddsData.Ptr, (uint)ddsData.Count, (.)&texture, &view);
|
||||
|
||||
view.Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Texture LoadTexture(Stream data, EditorTextureAssetLoaderConfig config)
|
||||
{
|
||||
Debug.Profiler.ProfileResourceFunction!();
|
||||
|
||||
List<LoadedSurface> surfaces = scope .();
|
||||
LoadedTextureInfo textureInfo;
|
||||
|
||||
// Make sure we clean up the pixel data
|
||||
defer { delete textureInfo.PixelData; }
|
||||
|
||||
|
||||
switch(GetTextureType(data))
|
||||
{
|
||||
case .DDS:
|
||||
|
||||
var v = data.Position;
|
||||
|
||||
//LoadDdsResourcePlatform(data);
|
||||
|
||||
data.Position = v;
|
||||
|
||||
Result<void> result = LoadDds(data, config, surfaces, out textureInfo);
|
||||
|
||||
if (result case .Err)
|
||||
return null;
|
||||
|
||||
case .PNG:
|
||||
Result<void> result = LoadPng(data, config, surfaces, out textureInfo);
|
||||
|
||||
if (result case .Err)
|
||||
return null;
|
||||
|
||||
case .Unknown:
|
||||
Log.EngineLogger.Error("Unknown texture format.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// Make the format SRGB or non-SRGB
|
||||
if (config.IsSRGB)
|
||||
textureInfo.PixelFormat = textureInfo.PixelFormat.GetSRGB();
|
||||
else
|
||||
textureInfo.PixelFormat = textureInfo.PixelFormat.GetNonSRGB();
|
||||
|
||||
Texture texture = CreateTexture(surfaces, textureInfo);
|
||||
|
||||
if (texture != null)
|
||||
{
|
||||
SetSampler(texture, config);
|
||||
texture.[Friend]Complete = true;
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
private static Texture CreateTexture(List<LoadedSurface> surfaces, LoadedTextureInfo textureInfo)
|
||||
{
|
||||
TextureSliceData[] slices = scope TextureSliceData[surfaces.Count];
|
||||
|
||||
for (int i < slices.Count)
|
||||
{
|
||||
slices[i] = .(surfaces[i].Data.Ptr, surfaces[i].Pitch, surfaces[i].SlicePitch);
|
||||
}
|
||||
|
||||
//slices[0].SlicePitch = (.)(surfaces[0].Pitch * textureInfo.Height);
|
||||
|
||||
switch (textureInfo.Dimension)
|
||||
{
|
||||
//case .Texture1D:
|
||||
case .Texture2D:
|
||||
if (textureInfo.IsCubeMap)
|
||||
{
|
||||
Texture2DDesc staging = .();
|
||||
|
||||
staging.Width = (.)textureInfo.Width;
|
||||
staging.Height = (.)textureInfo.Height;
|
||||
|
||||
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||
|
||||
staging.Format = (.)textureInfo.PixelFormat;
|
||||
|
||||
// TODO: allow enabling read/write
|
||||
staging.CpuAccess = .None;
|
||||
staging.Usage = .Default;
|
||||
|
||||
TextureCube cubeTexture = new TextureCube(staging);
|
||||
|
||||
//cubeTexture.SetData();
|
||||
|
||||
for (let surface in surfaces)
|
||||
{
|
||||
cubeTexture.SetData(surface.Data.Ptr, surface.Pitch / staging.Width, (TextureCubeFace)surface.CubeFace, (.)surface.ArrayIndex, (.)surface.MipLevel);
|
||||
}
|
||||
|
||||
return cubeTexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
Texture2DDesc staging = .();
|
||||
|
||||
staging.Width = (.)textureInfo.Width;
|
||||
staging.Height = (.)textureInfo.Height;
|
||||
|
||||
staging.MipLevels = (.)textureInfo.MipMapCount;
|
||||
staging.ArraySize = (.)textureInfo.ArraySize;
|
||||
|
||||
staging.Format = (.)textureInfo.PixelFormat;
|
||||
|
||||
// TODO: allow enabling read/write
|
||||
staging.CpuAccess = .None;
|
||||
staging.Usage = .Immutable;
|
||||
|
||||
Texture2D stagingTexture = new Texture2D(staging);
|
||||
|
||||
stagingTexture.SetData(slices);
|
||||
|
||||
/*for (let surface in surfaces)
|
||||
{
|
||||
stagingTexture.[Friend]PlatformSetData(surface.Data.Ptr, surface.Pitch / staging.Width, 0, 0, staging.Width, staging.Height, (.)surface.ArrayIndex, (.)surface.MipLevel, .Write);
|
||||
}*/
|
||||
|
||||
return stagingTexture;
|
||||
}
|
||||
default:
|
||||
Runtime.NotImplemented();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Result<void> LoadPng(Stream data, EditorTextureAssetLoaderConfig 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);
|
||||
|
||||
//Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
||||
//Texture2D texture = new Texture2D(desc);
|
||||
//texture.SetData<Color>((.)rawData);
|
||||
|
||||
// TODO: Generate mip maps
|
||||
|
||||
textureInfo.PixelData = pixelData;
|
||||
textureInfo.Width = width;
|
||||
textureInfo.Height = height;
|
||||
textureInfo.Depth = 1;
|
||||
|
||||
textureInfo.ArraySize = 1;
|
||||
textureInfo.MipMapCount = 1;
|
||||
|
||||
textureInfo.Dimension = .Texture2D;
|
||||
|
||||
textureInfo.IsCubeMap = false;
|
||||
|
||||
textureInfo.PixelFormat = config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm;
|
||||
|
||||
return .Ok;
|
||||
|
||||
//return texture;
|
||||
}
|
||||
|
||||
private static Result<void> LoadDds(Stream data, EditorTextureAssetLoaderConfig 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;
|
||||
}
|
||||
|
||||
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
||||
{
|
||||
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
|
||||
{
|
||||
texture.SamplerState = samplerState;
|
||||
}
|
||||
}
|
||||
|
||||
private static Texture2D _placeholder2D;
|
||||
private static TextureCube _placeholderCube;
|
||||
|
||||
private static Texture2D _error2D;
|
||||
private static TextureCube _errorCube;
|
||||
|
||||
public Asset GetPlaceholderAsset(Type assetType)
|
||||
{
|
||||
switch (assetType)
|
||||
{
|
||||
case typeof(TextureCube):
|
||||
if (_placeholderCube == null)
|
||||
{
|
||||
// TODO: immutable
|
||||
Texture2DDesc desc = .(1, 1, .R8G8B8A8_UNorm, 1, 1, .Default, .None);
|
||||
|
||||
_placeholderCube = new TextureCube(desc);
|
||||
_placeholderCube.SamplerState = SamplerStateManager.PointWrap;
|
||||
Color color = Color.Cyan;
|
||||
_placeholderCube.SetData<Color>(&color, .PositiveX);
|
||||
_placeholderCube.SetData<Color>(&color, .NegativeX);
|
||||
_placeholderCube.SetData<Color>(&color, .PositiveY);
|
||||
_placeholderCube.SetData<Color>(&color, .NegativeY);
|
||||
_placeholderCube.SetData<Color>(&color, .PositiveZ);
|
||||
_placeholderCube.SetData<Color>(&color, .NegativeZ);
|
||||
|
||||
Content.ManageAsset(_placeholderCube);
|
||||
_placeholderCube.ReleaseRef();
|
||||
|
||||
_placeholderCube.[Friend]Complete = false;
|
||||
}
|
||||
|
||||
return _placeholderCube;
|
||||
case typeof(Texture2D):
|
||||
fallthrough;
|
||||
default:
|
||||
if (_placeholder2D == null)
|
||||
{
|
||||
Texture2DDesc desc = .(1, 1, .R8G8B8A8_UNorm, 1, 1, .Immutable, .None);
|
||||
|
||||
_placeholder2D = new Texture2D(desc);
|
||||
_placeholder2D.SamplerState = SamplerStateManager.PointWrap;
|
||||
Color color = Color.Cyan;
|
||||
_placeholder2D.SetData<Color>(&color);
|
||||
|
||||
Content.ManageAsset(_placeholder2D);
|
||||
_placeholder2D.ReleaseRef();
|
||||
|
||||
_placeholder2D.[Friend]Complete = false;
|
||||
}
|
||||
|
||||
return _placeholder2D;
|
||||
}
|
||||
}
|
||||
|
||||
public Asset GetErrorAsset(Type assetType)
|
||||
{
|
||||
switch (assetType)
|
||||
{
|
||||
case typeof(TextureCube):
|
||||
if (_placeholderCube == null)
|
||||
{
|
||||
// TODO: immutable
|
||||
Texture2DDesc desc = .(2, 2, .R8G8B8A8_UNorm, 1, 1, .Default, .None);
|
||||
|
||||
_errorCube = new TextureCube(desc);
|
||||
_errorCube.SamplerState = SamplerStateManager.PointWrap;
|
||||
|
||||
Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink);
|
||||
|
||||
_errorCube.SetData<Color>(&color, .PositiveX);
|
||||
_errorCube.SetData<Color>(&color, .NegativeX);
|
||||
_errorCube.SetData<Color>(&color, .PositiveY);
|
||||
_errorCube.SetData<Color>(&color, .NegativeY);
|
||||
_errorCube.SetData<Color>(&color, .PositiveZ);
|
||||
_errorCube.SetData<Color>(&color, .NegativeZ);
|
||||
|
||||
Content.ManageAsset(_errorCube);
|
||||
_errorCube.ReleaseRef();
|
||||
|
||||
_errorCube.[Friend]Complete = false;
|
||||
}
|
||||
|
||||
return _placeholderCube;
|
||||
case typeof(Texture2D):
|
||||
fallthrough;
|
||||
default:
|
||||
if (_error2D == null)
|
||||
{
|
||||
Texture2DDesc desc = .(2, 2, .R8G8B8A8_UNorm, 1, 1, .Immutable, .None);
|
||||
|
||||
_error2D = new Texture2D(desc);
|
||||
_error2D.SamplerState = SamplerStateManager.PointWrap;
|
||||
|
||||
Color[4] color = .(Color.HotPink, Color.Black, Color.Black, Color.HotPink);
|
||||
|
||||
_error2D.SetData<Color>(&color);
|
||||
|
||||
Content.ManageAsset(_error2D);
|
||||
_error2D.ReleaseRef();
|
||||
|
||||
_placeholder2D.[Friend]Complete = true;
|
||||
}
|
||||
|
||||
return _error2D;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,9 +21,6 @@ namespace GlitchyEditor
|
||||
protected override IContentManager InitContentManager()
|
||||
{
|
||||
_contentManager = new EditorContentManager();
|
||||
_contentManager.RegisterAssetLoader<EditorTextureAssetLoader>();
|
||||
_contentManager.SetAsDefaultAssetLoader<EditorTextureAssetLoader>(".png", ".dds");
|
||||
_contentManager.SetAssetPropertiesEditor<EditorTextureAssetLoader>(=> TextureAssetPropertiesEditor.Factory);
|
||||
|
||||
_contentManager.RegisterAssetLoader<ModelAssetLoader>();
|
||||
_contentManager.SetAsDefaultAssetLoader<ModelAssetLoader>(".glb", ".gltf");
|
||||
@@ -41,9 +38,10 @@ namespace GlitchyEditor
|
||||
_contentManager.RegisterAssetProcessor<TextureProcessor>();
|
||||
_contentManager.RegisterAssetExporter<TextureExporter>();
|
||||
|
||||
_contentManager.ConfigureDefaultProcessing<TextureImporter, TextureProcessor, TextureExporter>(".png");
|
||||
_contentManager.ConfigureDefaultProcessing<TextureImporter, TextureProcessor, TextureExporter>(".png", ".dds");
|
||||
|
||||
_contentManager.SetResourcesDirectory("./Resources");
|
||||
_contentManager.SetGlobalAssetCacheDirectory(".cache");
|
||||
_contentManager.SetResourcesDirectory("Resources");
|
||||
|
||||
return _contentManager;
|
||||
}
|
||||
|
||||
@@ -95,9 +95,14 @@ class EditorContentManager : IContentManager
|
||||
_assetHierarchy.SetAssetsDirectory(_assetsDirectory);
|
||||
}
|
||||
|
||||
public void SetGlobalAssetCacheDirectory(StringView fileName)
|
||||
{
|
||||
_assetCache.SetGlobalCacheDirectory(fileName);
|
||||
}
|
||||
|
||||
public void SetAssetCacheDirectory(StringView fileName)
|
||||
{
|
||||
_assetCache.SetDirectory(fileName);
|
||||
_assetCache.SetProjectCacheDirectory(fileName);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
@@ -494,14 +499,11 @@ class EditorContentManager : IContentManager
|
||||
AssetNode assetNode = resultNode->Value;
|
||||
AssetFile file = assetNode.AssetFile;
|
||||
|
||||
CachedAsset cacheEntry = _assetCache.GetCacheEntry(handle);
|
||||
|
||||
Asset loadedAsset;
|
||||
|
||||
// TODO: Remove this check once we no longer need the old stuff
|
||||
if (cacheEntry != null)
|
||||
if (file.UseNewAssetPipeline)
|
||||
{
|
||||
// TODO: Load asset with new loaders
|
||||
loadedAsset = LoadFromCache(handle, blocking);
|
||||
}
|
||||
else
|
||||
@@ -522,7 +524,7 @@ class EditorContentManager : IContentManager
|
||||
}
|
||||
|
||||
// TODO: Support lazy loading for all asset types
|
||||
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
|
||||
if (true || blocking)
|
||||
{
|
||||
Stream stream = OpenStream(filePath, true);
|
||||
|
||||
@@ -948,22 +950,48 @@ class EditorContentManager : IContentManager
|
||||
{
|
||||
CachedAsset asset = _assetCache.GetCacheEntry(handle);
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
Result<TreeNode<AssetNode>> assetNodeResult = AssetHierarchy.GetNodeFromAssetHandle(handle);
|
||||
|
||||
if (assetNodeResult case .Ok(let assetNode))
|
||||
{
|
||||
_assetConverter.QueueForProcessing(assetNode->AssetFile, isBlocking);
|
||||
}
|
||||
|
||||
if (isBlocking)
|
||||
{
|
||||
asset = _assetCache.GetCacheEntry(handle);
|
||||
|
||||
Log.EngineLogger.Assert(asset != null, "Failed to load asset.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Return placeholder!
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Result<Stream> streamResult = _assetCache.OpenStream(asset);
|
||||
|
||||
// TODO: Actually return a placeholder, but they probably need rework too...
|
||||
if (streamResult case .Err)
|
||||
{
|
||||
// Return error
|
||||
return null;
|
||||
}
|
||||
|
||||
Stream dataStream = streamResult.Value;
|
||||
defer { delete dataStream; }
|
||||
|
||||
IProcessedAssetLoader loader = GetLoader(asset.AssetType);
|
||||
|
||||
switch (loader.Load(dataStream))
|
||||
if (loader.Load(dataStream) case .Ok(let loadedAsset))
|
||||
{
|
||||
case .Ok(let loadedAsset):
|
||||
return loadedAsset;
|
||||
case .Err:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return error
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -764,8 +764,8 @@ namespace GlitchyEditor
|
||||
_editor.CurrentProject = _currentProject;
|
||||
|
||||
String appAssemblyPath = scope String();
|
||||
_contentManager.SetAssetDirectory(_currentProject.AssetsFolder);
|
||||
_contentManager.SetAssetCacheDirectory(_currentProject.GetScopedPath!(".cache"));
|
||||
_contentManager.SetAssetDirectory(_currentProject.AssetsFolder);
|
||||
|
||||
_currentProject.PathInProject(appAssemblyPath, scope $"bin/{_currentProject.Name}.dll");
|
||||
|
||||
|
||||
@@ -4,14 +4,21 @@ namespace GlitchyEngine.Content;
|
||||
|
||||
public class AssetIdentifier
|
||||
{
|
||||
public const String ResourcesPrefix = "Resources/";
|
||||
public const String AssetsPrefix = "Assets/";
|
||||
|
||||
private String _fullIdentifier ~ delete:append _;
|
||||
|
||||
private bool _isResource;
|
||||
|
||||
private int _subassetSeperator;
|
||||
|
||||
public StringView FullIdentifier => _fullIdentifier;
|
||||
public StringView AssetIdentifier => _subassetSeperator > 0 ? StringView(_fullIdentifier, 0, _subassetSeperator) : _fullIdentifier;
|
||||
public StringView SubassetIdentifier => _subassetSeperator > 0 ? StringView(_fullIdentifier, _subassetSeperator + 1) : .();
|
||||
|
||||
public bool IsResource => _isResource;
|
||||
|
||||
[AllowAppend]
|
||||
public this(StringView assetIdentifier)
|
||||
{
|
||||
@@ -21,6 +28,8 @@ public class AssetIdentifier
|
||||
Fixup(_fullIdentifier);
|
||||
|
||||
_subassetSeperator = _fullIdentifier.IndexOf(':', 0);
|
||||
|
||||
_isResource = _fullIdentifier.StartsWith(ResourcesPrefix);
|
||||
}
|
||||
|
||||
[AllowAppend]
|
||||
|
||||
Reference in New Issue
Block a user