mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Start of async asset loading
- Refactored content manager and asset loaders - Asset placeholder - Error asset
This commit is contained in:
@@ -48,54 +48,15 @@ class EffectAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
|||||||
Effect effect = new Effect(file, assetIdentifier, contentManager);
|
Effect effect = new Effect(file, assetIdentifier, contentManager);
|
||||||
|
|
||||||
return effect;
|
return effect;
|
||||||
|
}
|
||||||
|
|
||||||
/*StreamReader reader = scope .(file);
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
|
||||||
String text = scope .();
|
|
||||||
|
|
||||||
reader.ReadToEnd(text);
|
|
||||||
|
|
||||||
MaterialFile materialFile = scope .();
|
|
||||||
|
|
||||||
var result = Bon.Deserialize<MaterialFile>(ref materialFile, text);
|
|
||||||
|
|
||||||
if (result case .Err)
|
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error("Failed to load material.");
|
return default;
|
||||||
return null;
|
|
||||||
// TODO: return error material
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect fx = new Effect(materialFile.Effect);
|
public Asset GetErrorAsset(Type assetType)
|
||||||
|
|
||||||
Material material = new Material(fx);
|
|
||||||
|
|
||||||
for (let (slotName, textureIdentifier) in materialFile.Textures)
|
|
||||||
{
|
{
|
||||||
Texture texture = contentManager.LoadAsset(textureIdentifier) as Texture;
|
return default;
|
||||||
|
|
||||||
if (texture == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load texture.");
|
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
|
||||||
|
|
||||||
material.SetTexture(slotName, texture);
|
|
||||||
}
|
|
||||||
|
|
||||||
fx.ReleaseRef();
|
|
||||||
|
|
||||||
/*for (let (slotName, textureIdentifier) in materialFile.Variables)
|
|
||||||
{
|
|
||||||
if (texture == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error("Failed to load texture.");
|
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
|
||||||
|
|
||||||
material.SetVariable(slotName, );
|
|
||||||
}*/
|
|
||||||
|
|
||||||
return material; //ModelLoader.LoadMesh(file, subAsset.Value, 0);*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -339,10 +339,9 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
Log.EngineLogger.Error("Failed to load material.");
|
Log.EngineLogger.Error("Failed to load material.");
|
||||||
Debug.SafeBreak();
|
Debug.SafeBreak();
|
||||||
return null;
|
return null;
|
||||||
// TODO: return error material
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Effect fx = Content.GetAsset<Effect>(contentManager.LoadAsset(materialFile.Effect), contentManager);//new Effect(materialFile.Effect);
|
Effect fx = Content.GetAsset<Effect>(contentManager.LoadAsset(materialFile.Effect, true), contentManager);
|
||||||
|
|
||||||
Material material = new Material(fx);
|
Material material = new Material(fx);
|
||||||
|
|
||||||
@@ -353,7 +352,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
if (texture.IsInvalid)
|
if (texture.IsInvalid)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
||||||
// TODO: LoadAsset should return an error texture.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
material.SetTexture(slotName, texture);
|
material.SetTexture(slotName, texture);
|
||||||
@@ -377,7 +375,7 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
material.SetVariable(slotName, value);
|
material.SetVariable(slotName, value);
|
||||||
case .None:
|
case .None:
|
||||||
default:
|
default:
|
||||||
Log.EngineLogger.Error("Errorre");
|
Log.EngineLogger.Error($"Unknown variable type of variable {slotName}: {variableValue}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -402,8 +400,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
materialFile.Textures = new .();
|
materialFile.Textures = new .();
|
||||||
materialFile.Variables = new .();
|
materialFile.Variables = new .();
|
||||||
|
|
||||||
//material.SetTexture();
|
|
||||||
|
|
||||||
for (let (slotName, texture) in material.[Friend]_textures)
|
for (let (slotName, texture) in material.[Friend]_textures)
|
||||||
{
|
{
|
||||||
Texture textureAsset = texture.Get();
|
Texture textureAsset = texture.Get();
|
||||||
@@ -419,7 +415,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||||
{
|
{
|
||||||
VariableValue variableValue = .None;
|
VariableValue variableValue = .None;
|
||||||
//Object variantValue = null;
|
|
||||||
|
|
||||||
let variable = effect.Variables[name];
|
let variable = effect.Variables[name];
|
||||||
|
|
||||||
@@ -445,7 +440,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||||
|
|
||||||
variableValue = .ColorRGBA(value);
|
variableValue = .ColorRGBA(value);
|
||||||
//variantValue = new box value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (variable.Type == .Float && variable.Rows == 1)
|
else if (variable.Type == .Float && variable.Rows == 1)
|
||||||
@@ -465,48 +459,6 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
material.GetVariable<Vector4>(variable.Name, let value);
|
material.GetVariable<Vector4>(variable.Name, let value);
|
||||||
variableValue = .Float4(value);
|
variableValue = .Float4(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*bool hasMin = TryGetValue(arguments, "Min", var min);
|
|
||||||
bool hasMax = TryGetValue(arguments, "Max", var max);
|
|
||||||
|
|
||||||
for (int r < variable.Rows)
|
|
||||||
{
|
|
||||||
switch (variable.Columns)
|
|
||||||
{
|
|
||||||
case 1:
|
|
||||||
material.GetVariable<float>(variable.Name, var value);
|
|
||||||
|
|
||||||
float[1] minV = hasMin ? min.Get<float[1]>() : .(float.MinValue);
|
|
||||||
float[1] maxV = hasMax ? max.Get<float[1]>() : .(float.MaxValue);
|
|
||||||
|
|
||||||
if (ImGui.EditVector<1>(displayName, ref *(float[1]*)&value, .(), 0.1f, 100.0f, minV, maxV))
|
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
case 2:
|
|
||||||
material.GetVariable<Vector2>(variable.Name, var value);
|
|
||||||
|
|
||||||
Vector2 minV = hasMin ? min.Get<Vector2>() : .(float.MinValue);
|
|
||||||
Vector2 maxV = hasMax ? max.Get<Vector2>() : .(float.MaxValue);
|
|
||||||
|
|
||||||
if (ImGui.EditVector2(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
case 3:
|
|
||||||
material.GetVariable<Vector3>(variable.Name, var value);
|
|
||||||
|
|
||||||
Vector3 minV = hasMin ? min.Get<Vector3>() : .(float.MinValue);
|
|
||||||
Vector3 maxV = hasMax ? max.Get<Vector3>() : .(float.MaxValue);
|
|
||||||
|
|
||||||
if (ImGui.EditVector3(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
case 4:
|
|
||||||
material.GetVariable<Vector4>(variable.Name, var value);
|
|
||||||
|
|
||||||
Vector4 minV = hasMin ? min.Get<Vector4>() : .(float.MinValue);
|
|
||||||
Vector4 maxV = hasMax ? max.Get<Vector4>() : .(float.MaxValue);
|
|
||||||
|
|
||||||
if (ImGui.EditVector4(displayName, ref value, .Zero, 0.1f, 100.0f, minV, maxV))
|
|
||||||
material.SetVariable(variable.Name, value);
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
materialFile.Variables.Add(new String(name), variableValue);
|
materialFile.Variables.Add(new String(name), variableValue);
|
||||||
@@ -523,4 +475,17 @@ class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
|||||||
|
|
||||||
return .Ok;
|
return .Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Material _placeholder;
|
||||||
|
Material _error;
|
||||||
|
|
||||||
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Asset GetErrorAsset(Type assetType)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,18 @@ class ModelAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
|||||||
|
|
||||||
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
|
public Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Assert(subAsset != null);
|
//Log.EngineLogger.Assert(subAsset != null);
|
||||||
|
|
||||||
return ModelLoader.LoadMesh(file, subAsset.Value, 0);
|
return ModelLoader.LoadMesh(file, subAsset ?? assetIdentifier, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Asset GetErrorAsset(Type assetType)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,65 +243,19 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
|||||||
case .PNG:
|
case .PNG:
|
||||||
texture = LoadPng(data, config);
|
texture = LoadPng(data, config);
|
||||||
case .Unknown:
|
case .Unknown:
|
||||||
Runtime.FatalError("Unknown image format.");
|
Log.EngineLogger.Error("Unknown texture format.");
|
||||||
|
texture = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(texture != null);
|
if (texture != null)
|
||||||
|
{
|
||||||
SetSampler(texture, config);
|
SetSampler(texture, config);
|
||||||
|
texture.[Friend]Complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReloadAsset(AssetFile assetFile, Stream data)
|
|
||||||
{
|
|
||||||
Texture reloadingTexture = assetFile.LoadedAsset as Texture;
|
|
||||||
|
|
||||||
if (reloadingTexture == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"{nameof(Self)}: Requested reload of \"{assetFile.FilePath}\" but it's not a Texture!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorTextureAssetLoaderConfig config = assetFile.AssetConfig.Config as EditorTextureAssetLoaderConfig;
|
|
||||||
|
|
||||||
if (config == null)
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"{nameof(Self)}: Config of asset \"{assetFile.FilePath}\" doesn't have the correct type!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(GetTextureType(data))
|
|
||||||
{
|
|
||||||
case .DDS:
|
|
||||||
ReloadDds(reloadingTexture as Texture2D, data, config);
|
|
||||||
case .PNG:
|
|
||||||
ReloadPng(reloadingTexture as Texture2D, data, config);
|
|
||||||
case .Unknown:
|
|
||||||
Runtime.FatalError("Unknown image format.");
|
|
||||||
}
|
|
||||||
|
|
||||||
SetSampler(reloadingTexture, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
|
||||||
{
|
|
||||||
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
|
|
||||||
{
|
|
||||||
texture.SamplerState = samplerState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadPng(Texture2D reloadingTexture, Stream data, EditorTextureAssetLoaderConfig config)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
using (Texture2D newTexture = LoadPng(data, config))
|
|
||||||
{
|
|
||||||
reloadingTexture.[Friend]SneakySwappyTexture(newTexture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Texture2D LoadPng(Stream data, EditorTextureAssetLoaderConfig config)
|
private static Texture2D LoadPng(Stream data, EditorTextureAssetLoaderConfig config)
|
||||||
{
|
{
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
@@ -313,40 +267,105 @@ class EditorTextureAssetLoader : IAssetLoader//, IReloadingAssetLoader
|
|||||||
if (result case .Err(let err))
|
if (result case .Err(let err))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
Log.EngineLogger.Error($"Failed to read data from stream. Texture: Error: {err}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* rawData = null;
|
||||||
|
defer
|
||||||
|
{
|
||||||
|
if (rawData != null)
|
||||||
|
LodePng.LodePng.Free(rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8* rawData = ?;
|
|
||||||
uint32 width = 0, height = 0;
|
uint32 width = 0, height = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceScope!("LodePng.LodePng.Decode32");
|
||||||
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
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 null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Log.EngineLogger.Assert(errorCode == 0, "Failed to load png File");
|
|
||||||
|
|
||||||
// TODO: load as SRGB because PNGs are usually not stored as linear
|
|
||||||
//Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
|
||||||
Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
Texture2DDesc desc = .(width, height, config.IsSRGB ? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
||||||
Texture2D texture = new Texture2D(desc);
|
Texture2D texture = new Texture2D(desc);
|
||||||
texture.SetData<Color>((.)rawData);
|
texture.SetData<Color>((.)rawData);
|
||||||
|
|
||||||
// TODO: Generate mip maps
|
// TODO: Generate mip maps
|
||||||
|
|
||||||
LodePng.LodePng.Free(rawData);
|
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReloadDds(Texture2D reloadingTexture, Stream data, EditorTextureAssetLoaderConfig config)
|
|
||||||
{
|
|
||||||
using (Texture2D newTexture = new [Friend]Texture2D(data))
|
|
||||||
{
|
|
||||||
reloadingTexture.[Friend]SneakySwappyTexture(newTexture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config)
|
private static Texture LoadDds(Stream data, EditorTextureAssetLoaderConfig config)
|
||||||
{
|
{
|
||||||
|
// TODO: Move the loading of Dds files here.
|
||||||
Texture2D texture = new [Friend]Texture2D(data);
|
Texture2D texture = new [Friend]Texture2D(data);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void SetSampler(Texture texture, EditorTextureAssetLoaderConfig config)
|
||||||
|
{
|
||||||
|
using (SamplerState samplerState = SamplerStateManager.GetSampler(config.SamplerStateDescription))
|
||||||
|
{
|
||||||
|
texture.SamplerState = samplerState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Texture2D _placeholder2D;
|
||||||
|
private static Texture2D _error2D;
|
||||||
|
|
||||||
|
public Asset GetPlaceholderAsset(Type assetType)
|
||||||
|
{
|
||||||
|
switch (assetType)
|
||||||
|
{
|
||||||
|
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(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ using GlitchyEngine.Content;
|
|||||||
using GlitchyEditor.Assets;
|
using GlitchyEditor.Assets;
|
||||||
using GlitchyEngine;
|
using GlitchyEngine;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using internal GlitchyEngine.Content.Asset;
|
||||||
|
|
||||||
namespace GlitchyEditor;
|
namespace GlitchyEditor;
|
||||||
|
|
||||||
@@ -100,6 +102,8 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
|
SwapInLoadedAssets();
|
||||||
|
|
||||||
if (!_reloadQueue.IsEmpty)
|
if (!_reloadQueue.IsEmpty)
|
||||||
{
|
{
|
||||||
for (AssetHandle handle in _reloadQueue)
|
for (AssetHandle handle in _reloadQueue)
|
||||||
@@ -112,6 +116,40 @@ class EditorContentManager : IContentManager
|
|||||||
_assetHierarchy.Update();
|
_assetHierarchy.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Replaces placeholders with the loaded assets
|
||||||
|
private void SwapInLoadedAssets()
|
||||||
|
{
|
||||||
|
// Don't take the lock if we have nothing to do.
|
||||||
|
if (_finishedEntries.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (_finishedEntriesLock.Enter())
|
||||||
|
{
|
||||||
|
while (_finishedEntries.Count > 0)
|
||||||
|
{
|
||||||
|
let (placeholder, asset) = _finishedEntries[0];
|
||||||
|
|
||||||
|
delete placeholder.LoadingTask;
|
||||||
|
|
||||||
|
if (asset == null)
|
||||||
|
placeholder.PlaceholderType = .Error;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO: I'm not sure whether AssetFiles are guaranteed to persist.
|
||||||
|
// Get the reference here because placeholder wont survive SwapAsset.
|
||||||
|
AssetFile file = placeholder.AssetFile;
|
||||||
|
file.[Friend]_loadedAsset = asset;
|
||||||
|
|
||||||
|
SwapAsset(placeholder, asset);
|
||||||
|
// SwapAsset increases RefCount, but this scope also holds a reference.
|
||||||
|
asset.ReleaseRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
_finishedEntries.RemoveAtFast(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public IAssetLoader GetDefaultAssetLoader(StringView fileExtension)
|
public IAssetLoader GetDefaultAssetLoader(StringView fileExtension)
|
||||||
{
|
{
|
||||||
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
|
if (_defaultAssetLoaders.TryGetValue(fileExtension, let value))
|
||||||
@@ -133,7 +171,9 @@ class EditorContentManager : IContentManager
|
|||||||
{
|
{
|
||||||
// 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.");
|
||||||
|
|
||||||
_assetLoaders.Add(new T());
|
T assetLoader = new T();
|
||||||
|
|
||||||
|
_assetLoaders.Add(assetLoader);
|
||||||
|
|
||||||
for (StringView ext in T.FileExtensions)
|
for (StringView ext in T.FileExtensions)
|
||||||
_supportedExtensions.Add(new String(ext));
|
_supportedExtensions.Add(new String(ext));
|
||||||
@@ -203,6 +243,14 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
_handleToAsset.TryGetValue(handle, out asset);
|
_handleToAsset.TryGetValue(handle, out asset);
|
||||||
|
|
||||||
|
if (var placeholder = asset as PlaceholderAsset)
|
||||||
|
{
|
||||||
|
if (placeholder.PlaceholderType == .Loading)
|
||||||
|
return placeholder.AssetLoader.GetPlaceholderAsset(assetType);
|
||||||
|
else if (placeholder.PlaceholderType == .Error)
|
||||||
|
return placeholder.AssetLoader.GetErrorAsset(assetType);
|
||||||
|
}
|
||||||
|
|
||||||
if (assetType == null)
|
if (assetType == null)
|
||||||
{
|
{
|
||||||
return asset;
|
return asset;
|
||||||
@@ -221,26 +269,26 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
private void ReloadAsset(AssetHandle handle)
|
private void ReloadAsset(AssetHandle handle)
|
||||||
{
|
{
|
||||||
Asset asset = null;
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
if (!_handleToAsset.TryGetValue(handle, out asset))
|
Asset oldAsset = null;
|
||||||
|
|
||||||
|
if (!_handleToAsset.TryGetValue(handle, out oldAsset))
|
||||||
{
|
{
|
||||||
Log.EngineLogger.Error("Can't reload! No asset exists for handle.");
|
Log.EngineLogger.Error("Can't reload! No asset exists for handle.");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.EngineLogger.AssertDebug(asset != null);
|
Log.EngineLogger.AssertDebug(oldAsset != null);
|
||||||
|
|
||||||
StringView oldIdentifier = asset.Identifier;
|
StringView oldIdentifier = oldAsset.Identifier;
|
||||||
|
|
||||||
GetResourceAndSubassetName(oldIdentifier, let resourceName, let subassetName);
|
GetResourceAndSubassetName(oldIdentifier, let resourceName, let subassetName);
|
||||||
|
|
||||||
String filePath = scope .();
|
String filePath = scope .();
|
||||||
GetResourceFilePath(resourceName, filePath);
|
GetResourceFilePath(resourceName, filePath);
|
||||||
|
|
||||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||||
|
|
||||||
if (resultNode case .Err)
|
if (resultNode case .Err)
|
||||||
@@ -255,6 +303,7 @@ class EditorContentManager : IContentManager
|
|||||||
|
|
||||||
Stream stream = GetStream(filePath);
|
Stream stream = GetStream(filePath);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
delete stream;
|
delete stream;
|
||||||
@@ -262,28 +311,20 @@ class EditorContentManager : IContentManager
|
|||||||
if (loadedAsset == null)
|
if (loadedAsset == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
loadedAsset.Identifier = oldIdentifier;
|
|
||||||
loadedAsset.[Friend]_handle = handle;
|
|
||||||
|
|
||||||
// Remove asset
|
|
||||||
_identiferToHandle.Remove(oldIdentifier);
|
|
||||||
Asset oldAsset = _handleToAsset[handle];
|
|
||||||
oldAsset.ReleaseRef();
|
|
||||||
|
|
||||||
_handleToAsset[handle] = loadedAsset;
|
|
||||||
_identiferToHandle.Add(loadedAsset.Identifier, handle);
|
|
||||||
|
|
||||||
file.[Friend]_loadedAsset = loadedAsset;
|
file.[Friend]_loadedAsset = loadedAsset;
|
||||||
|
|
||||||
|
SwapAsset(oldAsset, loadedAsset);
|
||||||
|
// SwapAsset increases RefCount, but this scope also holds a reference.
|
||||||
|
loadedAsset.ReleaseRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the resource name and, if it exists, the subasset name.
|
/// Returns the resource name and, if it exists, the subasset name.
|
||||||
private void GetResourceAndSubassetName(StringView identifier, out StringView resourceName, out StringView? subassetName)
|
private void GetResourceAndSubassetName(StringView identifier, out StringView resourceName, out StringView? subassetName)
|
||||||
{
|
{
|
||||||
// Find subasset name
|
|
||||||
int poundIndex = identifier.IndexOf('#');
|
int poundIndex = identifier.IndexOf('#');
|
||||||
|
|
||||||
resourceName = poundIndex == -1 ? identifier : identifier.Substring(0, poundIndex);
|
resourceName = (poundIndex != -1) ? identifier.Substring(0, poundIndex) : identifier;
|
||||||
subassetName = identifier.Substring(poundIndex + 1);
|
subassetName = (poundIndex != -1) ? identifier.Substring(poundIndex + 1) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetResourceFilePath(StringView resourceName, String filePath)
|
private void GetResourceFilePath(StringView resourceName, String filePath)
|
||||||
@@ -293,25 +334,66 @@ class EditorContentManager : IContentManager
|
|||||||
Path.Fixup(filePath);
|
Path.Fixup(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetHandle LoadAsset(StringView identifier)
|
private enum PlaceholderType
|
||||||
{
|
{
|
||||||
|
Loading,
|
||||||
|
Error
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PlaceholderAsset : Asset
|
||||||
|
{
|
||||||
|
public AssetFile AssetFile {get; private set;}
|
||||||
|
public Task LoadingTask {get;set;}
|
||||||
|
public IAssetLoader AssetLoader {get; private set;}
|
||||||
|
public PlaceholderType PlaceholderType {get; set;}
|
||||||
|
|
||||||
|
public this(AssetFile assetFile, IAssetLoader assetLoader, PlaceholderType placeholderType)
|
||||||
|
{
|
||||||
|
AssetFile = assetFile;
|
||||||
|
AssetLoader = assetLoader;
|
||||||
|
PlaceholderType = placeholderType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private append Monitor _finishedEntriesLock = .();
|
||||||
|
private append List<(PlaceholderAsset placeholder, Asset newAsset)> _finishedEntries = .();
|
||||||
|
|
||||||
|
private class MissingAsset : Asset {}
|
||||||
|
|
||||||
|
public class AssetIdentifier
|
||||||
|
{
|
||||||
|
public const char8 DirectorySeparatorChar = '/';
|
||||||
|
|
||||||
|
public static void Fixup(String assetIdentifier)
|
||||||
|
{
|
||||||
|
const String DotSeperator = $".{DirectorySeparatorChar}";
|
||||||
|
const String SeperatorDot = $"{DirectorySeparatorChar}.";
|
||||||
|
|
||||||
|
assetIdentifier.Replace('\\', DirectorySeparatorChar);
|
||||||
|
assetIdentifier.Replace(DotSeperator, "");
|
||||||
|
assetIdentifier.Replace(SeperatorDot, "");
|
||||||
|
|
||||||
|
if (assetIdentifier.StartsWith(DirectorySeparatorChar))
|
||||||
|
assetIdentifier.Remove(0, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AssetHandle LoadAsset(StringView identifier, bool blocking = false)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
// Todo: How strict should we be on paths?
|
// Todo: How strict should we be on paths?
|
||||||
String fixedIdentifier = scope String(identifier);
|
String fixedIdentifier = scope String(identifier);
|
||||||
// TODO: Fixup is more of a filesystem thingy... we might want to use our own function
|
AssetIdentifier.Fixup(fixedIdentifier);
|
||||||
Path.Fixup(fixedIdentifier);
|
|
||||||
|
|
||||||
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
|
if (_identiferToHandle.TryGetValue(fixedIdentifier, let asset))
|
||||||
{
|
|
||||||
return asset;
|
return asset;
|
||||||
}
|
|
||||||
|
|
||||||
GetResourceAndSubassetName(fixedIdentifier, let resourceName, let subassetName);
|
GetResourceAndSubassetName(fixedIdentifier, let resourceName, let subassetName);
|
||||||
|
|
||||||
String filePath = scope .();
|
String filePath = scope .();
|
||||||
GetResourceFilePath(resourceName, filePath);
|
GetResourceFilePath(resourceName, filePath);
|
||||||
|
|
||||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
|
||||||
|
|
||||||
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
Result<TreeNode<AssetNode>> resultNode = AssetHierarchy.GetNodeFromPath(filePath);
|
||||||
|
|
||||||
if (resultNode case .Err)
|
if (resultNode case .Err)
|
||||||
@@ -327,14 +409,37 @@ class EditorContentManager : IContentManager
|
|||||||
// TODO: what are we supposed to do if we don't find a loader? Sure not crash...
|
// TODO: what are we supposed to do if we don't find a loader? Sure not crash...
|
||||||
Log.EngineLogger.AssertDebug(assetLoader != null);
|
Log.EngineLogger.AssertDebug(assetLoader != null);
|
||||||
|
|
||||||
|
Asset loadedAsset;
|
||||||
|
|
||||||
|
// TODO: Support lazy loading for all asset types
|
||||||
|
if (!(assetLoader is EditorTextureAssetLoader) || blocking)
|
||||||
|
{
|
||||||
Stream stream = GetStream(filePath);
|
Stream stream = GetStream(filePath);
|
||||||
|
|
||||||
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||||
|
|
||||||
delete stream;
|
delete stream;
|
||||||
|
|
||||||
if (loadedAsset == null)
|
if (loadedAsset == null)
|
||||||
return .Invalid;
|
return .Invalid;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlaceholderAsset placeholder = new PlaceholderAsset(file, assetLoader, .Loading);
|
||||||
|
|
||||||
|
String filePath2 = new String(filePath);
|
||||||
|
String newResourceName = new String(resourceName);
|
||||||
|
String newSesourceName = subassetName == null ? null : new String(subassetName.Value);
|
||||||
|
|
||||||
|
placeholder.LoadingTask = new Task(new () => {
|
||||||
|
AsyncLoadAsset(placeholder, filePath2, assetLoader, file,
|
||||||
|
newResourceName, newSesourceName);
|
||||||
|
});
|
||||||
|
|
||||||
|
ThreadPool.QueueUserWorkItem(placeholder.LoadingTask);
|
||||||
|
|
||||||
|
loadedAsset = placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
loadedAsset.Identifier = fixedIdentifier;
|
loadedAsset.Identifier = fixedIdentifier;
|
||||||
AssetHandle handle = ManageAsset(loadedAsset);
|
AssetHandle handle = ManageAsset(loadedAsset);
|
||||||
@@ -349,6 +454,25 @@ class EditorContentManager : IContentManager
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AsyncLoadAsset(PlaceholderAsset placeholder, String filePath, IAssetLoader assetLoader, AssetFile file, String resourceName, String subassetName)
|
||||||
|
{
|
||||||
|
Debug.Profiler.ProfileResourceFunction!();
|
||||||
|
|
||||||
|
Stream stream = GetStream(filePath);
|
||||||
|
|
||||||
|
Asset loadedAsset = assetLoader.LoadAsset(stream, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||||
|
|
||||||
|
delete stream;
|
||||||
|
delete filePath;
|
||||||
|
delete resourceName;
|
||||||
|
delete subassetName;
|
||||||
|
|
||||||
|
using (_finishedEntriesLock.Enter())
|
||||||
|
{
|
||||||
|
_finishedEntries.Add((placeholder, loadedAsset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the asset loader that has to be used for the given file.
|
/// Gets the asset loader that has to be used for the given file.
|
||||||
IAssetLoader GetAssetLoader(AssetFile file)
|
IAssetLoader GetAssetLoader(AssetFile file)
|
||||||
{
|
{
|
||||||
@@ -483,9 +607,10 @@ class EditorContentManager : IContentManager
|
|||||||
AssetHandle handle = .();
|
AssetHandle handle = .();
|
||||||
|
|
||||||
// Generate until we find a unique key (shouldn't happen too often)
|
// Generate until we find a unique key (shouldn't happen too often)
|
||||||
while (_handleToAsset.ContainsKey(handle))
|
while (handle.IsInvalid || _handleToAsset.ContainsKey(handle))
|
||||||
{
|
{
|
||||||
handle = .();
|
handle = .();
|
||||||
|
Log.EngineLogger.Trace("Handle was invalid or already taken.");
|
||||||
// TODO: perhaps test how often this happens.
|
// TODO: perhaps test how often this happens.
|
||||||
// If this happens too often we could use a different random generator
|
// If this happens too often we could use a different random generator
|
||||||
}
|
}
|
||||||
@@ -500,9 +625,26 @@ class EditorContentManager : IContentManager
|
|||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void SwapAsset(Asset oldAsset, Asset newAsset)
|
||||||
|
{
|
||||||
|
newAsset.Identifier = oldAsset.Identifier;
|
||||||
|
newAsset._contentManager = this;
|
||||||
|
newAsset._handle = oldAsset.Handle;
|
||||||
|
|
||||||
|
_handleToAsset[oldAsset.Handle] = newAsset;
|
||||||
|
|
||||||
|
if (_identiferToHandle.ContainsKey(oldAsset.Identifier))
|
||||||
|
{
|
||||||
|
_identiferToHandle.Remove(oldAsset.Identifier);
|
||||||
|
_identiferToHandle.Add(newAsset.Identifier, newAsset.Handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
newAsset.AddRef();
|
||||||
|
oldAsset.ReleaseRef();
|
||||||
|
}
|
||||||
|
|
||||||
public void UnmanageAsset(AssetHandle handle)
|
public void UnmanageAsset(AssetHandle handle)
|
||||||
{
|
{
|
||||||
//Log.EngineLogger.AssertDebug(_handles.ContainsValue(handle), "Handle isn't managed by this content manager.");
|
|
||||||
Log.EngineLogger.AssertDebug(_handleToAsset.ContainsKey(handle), "Handle doesn't correspond to an asset.");
|
Log.EngineLogger.AssertDebug(_handleToAsset.ContainsKey(handle), "Handle doesn't correspond to an asset.");
|
||||||
|
|
||||||
Asset asset = _handleToAsset[handle];
|
Asset asset = _handleToAsset[handle];
|
||||||
@@ -520,16 +662,14 @@ class EditorContentManager : IContentManager
|
|||||||
/// Note: This will not release any assets.
|
/// Note: This will not release any assets.
|
||||||
private void UnmanageAllAssets()
|
private void UnmanageAllAssets()
|
||||||
{
|
{
|
||||||
for (let (_, assetHandle) in _identiferToHandle)
|
for (let (handle, _) in _handleToAsset)
|
||||||
{
|
{
|
||||||
UnmanageAsset(assetHandle);
|
UnmanageAsset(handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
public void AssetMoved(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
||||||
{
|
{
|
||||||
// TODO: this is much harder with asste handles that are basically hashed identifiers!
|
|
||||||
|
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
|
|
||||||
if (oldIdentifier == newIdentifier)
|
if (oldIdentifier == newIdentifier)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace GlitchyEditor
|
|||||||
|
|
||||||
public this(String texturePath, Vector2 iconSize)
|
public this(String texturePath, Vector2 iconSize)
|
||||||
{
|
{
|
||||||
_texture = Content.LoadAsset(texturePath);//new Texture2D(texturePath);
|
_texture = Content.LoadAsset(texturePath, null, true);
|
||||||
|
|
||||||
Vector2 pen = .();
|
Vector2 pen = .();
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using System.IO;
|
|||||||
namespace GlitchyEngine.Content;
|
namespace GlitchyEngine.Content;
|
||||||
|
|
||||||
[BonTarget]
|
[BonTarget]
|
||||||
class Asset : RefCounter
|
abstract class Asset : RefCounter
|
||||||
{
|
{
|
||||||
internal AssetHandle _handle = .Invalid;
|
internal AssetHandle _handle = .Invalid;
|
||||||
|
|
||||||
@@ -22,14 +22,11 @@ class Asset : RefCounter
|
|||||||
public StringView Identifier
|
public StringView Identifier
|
||||||
{
|
{
|
||||||
get => _identifier;
|
get => _identifier;
|
||||||
set
|
internal set => _identifier.Set(value);
|
||||||
{
|
}
|
||||||
_contentManager?.UpdateAssetIdentifier(this, _identifier, value);
|
|
||||||
|
|
||||||
_identifier.Set(value);
|
/// If true the asset is completely loaded. If false it is only partially loaded (if at all).
|
||||||
// TODO: do we need to tell the content manager, that the name changed?
|
public bool Complete { get; internal set; }
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: do we need unmanaged assets? Probably not...
|
// TODO: do we need unmanaged assets? Probably not...
|
||||||
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
|
/// Gets the content manager that manages this asset; or null if this asset isn't managed.
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ struct AssetHandle : IHashable
|
|||||||
private UUID _uuid;
|
private UUID _uuid;
|
||||||
|
|
||||||
/// Defines an asset that is invalid.
|
/// Defines an asset that is invalid.
|
||||||
public const AssetHandle Invalid = .(UUID(0xAAAA'AAAA'AAAA'AAAA));
|
public const AssetHandle Invalid = .(UUID(0));
|
||||||
|
|
||||||
public bool IsValid => this == .Invalid;
|
public bool IsValid => this != .Invalid;
|
||||||
public bool IsInvalid => !IsValid;
|
public bool IsInvalid => this == .Invalid;
|
||||||
|
|
||||||
/// Create a new random AssetHandle
|
/// Create a new random AssetHandle
|
||||||
public this()
|
public this()
|
||||||
@@ -49,8 +49,8 @@ struct AssetHandle<T> where T : Asset
|
|||||||
|
|
||||||
public const Self Invalid = .();
|
public const Self Invalid = .();
|
||||||
|
|
||||||
public bool IsValid => this == .Invalid;
|
public bool IsValid => this != .Invalid;
|
||||||
public bool IsInvalid => !IsValid;
|
public bool IsInvalid => this == .Invalid;
|
||||||
|
|
||||||
public this(AssetHandle handle, IContentManager contentManager = null)
|
public this(AssetHandle handle, IContentManager contentManager = null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,19 +57,25 @@ namespace GlitchyEngine.Content
|
|||||||
/// @param contentManager The content manager used to load the asset.
|
/// @param contentManager The content manager used to load the asset.
|
||||||
/// @returns The loaded asset.
|
/// @returns The loaded asset.
|
||||||
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
|
Asset LoadAsset(Stream file, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
|
||||||
|
|
||||||
|
/// Returns the placeholder asset.
|
||||||
|
Asset GetPlaceholderAsset(Type assetType);
|
||||||
|
|
||||||
|
/// Returns the error asset.
|
||||||
|
Asset GetErrorAsset(Type assetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static class Content
|
static class Content
|
||||||
{
|
{
|
||||||
/// Loads the specified asset with the given contentManager or the current applications content manager.
|
/// Loads the specified asset with the given contentManager or the current applications content manager.
|
||||||
public static AssetHandle LoadAsset(StringView assetIdentifier, IContentManager contentManager = null)
|
public static AssetHandle LoadAsset(StringView assetIdentifier, IContentManager contentManager = null, bool blocking = false)
|
||||||
{
|
{
|
||||||
var contentManager;
|
var contentManager;
|
||||||
|
|
||||||
if (contentManager == null)
|
if (contentManager == null)
|
||||||
contentManager = Application.Get().ContentManager;
|
contentManager = Application.Get().ContentManager;
|
||||||
|
|
||||||
AssetHandle handle = contentManager.LoadAsset(assetIdentifier);
|
AssetHandle handle = contentManager.LoadAsset(assetIdentifier, blocking);
|
||||||
|
|
||||||
return handle;
|
return handle;
|
||||||
}
|
}
|
||||||
@@ -111,7 +117,7 @@ namespace GlitchyEngine.Content
|
|||||||
interface IContentManager
|
interface IContentManager
|
||||||
{
|
{
|
||||||
/// Loads the Asset with the given handle and returns the handle.
|
/// Loads the Asset with the given handle and returns the handle.
|
||||||
AssetHandle LoadAsset(StringView assetIdentifier);
|
AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false);
|
||||||
|
|
||||||
/// Returns the asset for the given handle or null, if it isn't loaded.
|
/// Returns the asset for the given handle or null, if it isn't loaded.
|
||||||
Asset GetAsset(AssetHandle handle)
|
Asset GetAsset(AssetHandle handle)
|
||||||
@@ -128,10 +134,6 @@ namespace GlitchyEngine.Content
|
|||||||
/// The content manager will no longer manage the asset.
|
/// The content manager will no longer manage the asset.
|
||||||
void UnmanageAsset(AssetHandle asset);
|
void UnmanageAsset(AssetHandle asset);
|
||||||
|
|
||||||
// TODO: Maybe calling UnmanageAsset -> ManageAsset is enough....
|
|
||||||
/// Provides a method for the asset to tell its content manager that the identifer changed.
|
|
||||||
void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier);
|
|
||||||
|
|
||||||
/// Returns a data stream for the given asset.
|
/// Returns a data stream for the given asset.
|
||||||
Stream GetStream(StringView assetIdentifier);
|
Stream GetStream(StringView assetIdentifier);
|
||||||
|
|
||||||
@@ -149,7 +151,7 @@ namespace GlitchyEngine.Content
|
|||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AssetHandle LoadAsset(StringView assetIdentifier)
|
public AssetHandle LoadAsset(StringView assetIdentifier, bool blocking = false)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
@@ -169,11 +171,6 @@ namespace GlitchyEngine.Content
|
|||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateAssetIdentifier(Asset asset, StringView oldIdentifier, StringView newIdentifier)
|
|
||||||
{
|
|
||||||
Runtime.NotImplemented();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Stream GetStream(StringView assetIdentifier)
|
public Stream GetStream(StringView assetIdentifier)
|
||||||
{
|
{
|
||||||
Runtime.NotImplemented();
|
Runtime.NotImplemented();
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ namespace GlitchyEngine.Renderer
|
|||||||
LoadDdsResourcePlatform(stream, ref nativeTexture);
|
LoadDdsResourcePlatform(stream, ref nativeTexture);
|
||||||
|
|
||||||
let resType = nativeTexture.GetResourceType();
|
let resType = nativeTexture.GetResourceType();
|
||||||
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture \"{_path}\" is not a 2D texture (it is {resType}).");
|
Log.EngineLogger.Assert(resType == .Texture2D, scope $"The texture is not a 2D texture (it is {resType}).");
|
||||||
|
|
||||||
nativeTexture.GetDescription(out nativeDesc);
|
nativeTexture.GetDescription(out nativeDesc);
|
||||||
}
|
}
|
||||||
@@ -261,13 +261,6 @@ namespace GlitchyEngine.Renderer
|
|||||||
{
|
{
|
||||||
return .(_nativeResourceView, _samplerState?.nativeSamplerState);
|
return .(_nativeResourceView, _samplerState?.nativeSamplerState);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void PlatformSneakySwappyTexture(Texture2D otherTexture)
|
|
||||||
{
|
|
||||||
Swap!(nativeDesc, otherTexture.nativeDesc);
|
|
||||||
Swap!(nativeTexture, otherTexture.nativeTexture);
|
|
||||||
Swap!(_nativeResourceView, otherTexture._nativeResourceView);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension TextureCube
|
extension TextureCube
|
||||||
|
|||||||
@@ -63,92 +63,18 @@ namespace GlitchyEngine.Renderer
|
|||||||
|
|
||||||
public class Texture2D : Texture
|
public class Texture2D : Texture
|
||||||
{
|
{
|
||||||
protected String _path ~ delete _;
|
|
||||||
|
|
||||||
//public override extern uint32 Width {get;}
|
//public override extern uint32 Width {get;}
|
||||||
//public override extern uint32 Height {get;}
|
//public override extern uint32 Height {get;}
|
||||||
public override uint32 Depth => 1;
|
public override uint32 Depth => 1;
|
||||||
//public override extern uint32 ArraySize {get;}
|
//public override extern uint32 ArraySize {get;}
|
||||||
//public override extern uint32 MipLevels {get;}
|
//public override extern uint32 MipLevels {get;}
|
||||||
|
|
||||||
private this(StringView path, bool pngSrgb = false)
|
|
||||||
{
|
|
||||||
_path = new String(path);
|
|
||||||
LoadTexture(pngSrgb);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove
|
// TODO: remove
|
||||||
private this(Stream data)
|
private this(Stream data)
|
||||||
{
|
{
|
||||||
LoadDds(data);
|
LoadDds(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PngMagicWord = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
|
|
||||||
const String DdsMagicWord = "DDS ";
|
|
||||||
|
|
||||||
private void LoadTexture(bool pngSrgb)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
Stream data = Application.Get().ContentManager.GetStream(_path);
|
|
||||||
defer delete data;
|
|
||||||
|
|
||||||
var readResult = data.Read<char8[8]>();
|
|
||||||
|
|
||||||
data.Position = 0;
|
|
||||||
|
|
||||||
char8[8] magicWord;
|
|
||||||
|
|
||||||
if (readResult case .Ok(out magicWord))
|
|
||||||
{
|
|
||||||
StringView strView = .(&magicWord, magicWord.Count);
|
|
||||||
|
|
||||||
if (strView.StartsWith(PngMagicWord))
|
|
||||||
{
|
|
||||||
LoadPng(data, pngSrgb);
|
|
||||||
}
|
|
||||||
else if (strView.StartsWith(DdsMagicWord))
|
|
||||||
{
|
|
||||||
LoadDds(data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Runtime.FatalError("Unknown image format.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void LoadPng(Stream stream, bool srgb)
|
|
||||||
{
|
|
||||||
Debug.Profiler.ProfileResourceFunction!();
|
|
||||||
|
|
||||||
uint8[] pngData = new:ScopedAlloc! uint8[stream.Length];
|
|
||||||
|
|
||||||
var result = stream.TryRead(pngData);
|
|
||||||
|
|
||||||
if (result case .Err(let err))
|
|
||||||
{
|
|
||||||
Log.EngineLogger.Error($"Failed to read data from stream. Texture: \"{_path}\", Error: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8* rawData = ?;
|
|
||||||
uint32 width = 0, height = 0;
|
|
||||||
|
|
||||||
uint32 errorCode = LodePng.LodePng.Decode32(&rawData, &width, &height, pngData.Ptr, (.)pngData.Count);
|
|
||||||
|
|
||||||
Debug.Assert(errorCode == 0, "Failed to load png File");
|
|
||||||
|
|
||||||
// TODO: load as SRGB because PNGs are usually not stored as linear
|
|
||||||
//Texture2DDesc desc = .(width, height, .R8G8B8A8_UNorm_SRGB, 1, 1, .Immutable);
|
|
||||||
Texture2DDesc desc = .(width, height, srgb? .R8G8B8A8_UNorm_SRGB : .R8G8B8A8_UNorm, 1, 1, .Immutable);
|
|
||||||
|
|
||||||
PrepareTexturePlatform(desc, false);
|
|
||||||
|
|
||||||
SetData<Color>((.)rawData);
|
|
||||||
|
|
||||||
LodePng.LodePng.Free(rawData);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void LoadDds(Stream stream)
|
protected void LoadDds(Stream stream)
|
||||||
{
|
{
|
||||||
LoadDdsPlatform(stream);
|
LoadDdsPlatform(stream);
|
||||||
|
|||||||
Reference in New Issue
Block a user