mirror of
https://github.com/aharabada/glitchy-engine-beef.git
synced 2026-09-05 13:01:52 +00:00
Basic material serialisation
This commit is contained in:
@@ -4,3 +4,6 @@ WorkspaceFolders = {GlitchyEngine = ["GlitchyEngine", "GlitchLog", "GlitchyEngin
|
||||
|
||||
[Workspace]
|
||||
StartupProject = "GlitchyEditor"
|
||||
|
||||
[Configs.Debug.Win64]
|
||||
AllocStackTraceDepth = 12
|
||||
|
||||
@@ -1,7 +1,28 @@
|
||||
{
|
||||
Effect = "content/Shaders/myEffect.hlsl",
|
||||
Textures =
|
||||
[
|
||||
"AlbedoTexture": "Textures/TestMat/rustediron2_albedo.png"
|
||||
]
|
||||
Effect = "content/Shaders/myEffect.hlsl",
|
||||
Textures = [
|
||||
"AlbedoTexture": "Textures/TestMat/rustediron2_albedo.png"
|
||||
],
|
||||
Variables = [
|
||||
"AlbedoColor": .ColorRGBA{
|
||||
Value = {
|
||||
R = 1,
|
||||
G = 1,
|
||||
B = 1,
|
||||
A = 1
|
||||
}
|
||||
},
|
||||
"NormalScaling": .Float2{
|
||||
Value = {
|
||||
X = 1,
|
||||
Y = 1
|
||||
}
|
||||
},
|
||||
"MetallicFactor": .Float{
|
||||
Value = 1
|
||||
},
|
||||
"RoughnessFactor": .Float{
|
||||
Value = 1
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
using GlitchyEngine;
|
||||
using GlitchyEngine.Collections;
|
||||
using GlitchyEngine.Renderer;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace GlitchyEditor.Assets;
|
||||
|
||||
public class AssetNode
|
||||
{
|
||||
public String Name ~ delete _;
|
||||
public String Path ~ delete _;
|
||||
|
||||
public bool IsDirectory;
|
||||
|
||||
public AssetFile AssetFile ~ delete _;
|
||||
|
||||
public List<SubAsset> SubAssets ~ {
|
||||
SubAssets?.ClearAndDeleteItems();
|
||||
delete SubAssets;
|
||||
}
|
||||
|
||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
||||
}
|
||||
|
||||
public class SubAsset
|
||||
{
|
||||
public AssetNode Asset;
|
||||
public String Name ~ delete _;
|
||||
//public String AssetInternalPath ~ delete _;
|
||||
|
||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
||||
}
|
||||
|
||||
class AssetHierarchy
|
||||
{
|
||||
FileSystemWatcher fsw ~ {
|
||||
_.StopRaisingEvents();
|
||||
delete _;
|
||||
};
|
||||
|
||||
bool _fileSystemDirty = false;
|
||||
|
||||
internal TreeNode<AssetNode> _assetHierarchy = null ~ DeleteTreeAndChildren!(_);
|
||||
private append Dictionary<StringView, TreeNode<AssetNode>> _pathToAssetNode = .();
|
||||
|
||||
private append String _contentDirectory = .();
|
||||
|
||||
private EditorContentManager _contentManager;
|
||||
|
||||
public StringView ContentDirectory
|
||||
{
|
||||
get => _contentDirectory;
|
||||
private set
|
||||
{
|
||||
_contentDirectory.Clear();
|
||||
_contentDirectory.Append(value);
|
||||
Path.Fixup(_contentDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public this(EditorContentManager contentManager)
|
||||
{
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public void SetContentDirectory(StringView contentDirectory)
|
||||
{
|
||||
ContentDirectory = contentDirectory;
|
||||
|
||||
_fileSystemDirty = true;
|
||||
|
||||
SetupFileSystemWatcher();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
/// Initializes the FSW for the current ContentDirectory and registers the events.
|
||||
private void SetupFileSystemWatcher()
|
||||
{
|
||||
delete fsw;
|
||||
fsw = new FileSystemWatcher(_contentDirectory);
|
||||
fsw.IncludeSubdirectories = true;
|
||||
|
||||
fsw.OnChanged.Add(new (filename) => {
|
||||
// Note: Gets fired for a directory if a file inside it is created/removed
|
||||
|
||||
Log.EngineLogger.Trace($"File content changed (\"{filename}\")");
|
||||
//_fileSystemDirty = true;
|
||||
|
||||
FileContentChanged(filename);
|
||||
});
|
||||
|
||||
fsw.OnCreated.Add(new (filename) => {
|
||||
Log.EngineLogger.Trace($"File created (\"{filename}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
});
|
||||
|
||||
fsw.OnDeleted.Add(new (filename) => {
|
||||
Log.EngineLogger.Trace($"File deleted (\"{filename}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
});
|
||||
|
||||
fsw.OnRenamed.Add(new (oldName, newName) => {
|
||||
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
/*String contentFilePath = scope String();
|
||||
|
||||
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
|
||||
|
||||
//_fileSystemDirty = true;
|
||||
TreeNode<AssetNode> fileNode = GetNodeFromPath(contentFilePath);
|
||||
fileNode->*/
|
||||
});
|
||||
|
||||
fsw.StartRaisingEvents();
|
||||
}
|
||||
|
||||
/// Gets the tree node for the given filePath or null, if the file/directory doesn't exist.
|
||||
/// @param filePath the path for which to return the tree node.
|
||||
/// @remarks Do not hold a reference to the TreeNode because it can become invalid when the file hierarchy changes.
|
||||
public Result<TreeNode<AssetNode>> GetNodeFromPath(StringView filePath)
|
||||
{
|
||||
if (_pathToAssetNode.TryGetValue(filePath, let treeNode))
|
||||
{
|
||||
return treeNode;
|
||||
}
|
||||
|
||||
return .Err;
|
||||
}
|
||||
|
||||
public bool FileExists(StringView filePath)
|
||||
{
|
||||
return _pathToAssetNode.ContainsKey(filePath);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// TODO: do we really need to do this in the update loop?
|
||||
if (_fileSystemDirty)
|
||||
{
|
||||
UpdateFiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Rebuilds the asset file hierarchy.
|
||||
private void UpdateFiles()
|
||||
{
|
||||
Log.EngineLogger.Trace($"Updating asset hierarchy");
|
||||
|
||||
if (_assetHierarchy == null)
|
||||
{
|
||||
// TODO: move to init?
|
||||
|
||||
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
|
||||
_assetHierarchy->Path = new String(ContentDirectory);
|
||||
_assetHierarchy->Name = new String("Content");
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
|
||||
|
||||
_pathToAssetNode.Add(ContentDirectory, _assetHierarchy);
|
||||
}
|
||||
|
||||
void HandleFile(AssetNode node)
|
||||
{
|
||||
String identifier = scope .(node.Path.Length);
|
||||
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
|
||||
|
||||
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
|
||||
}
|
||||
|
||||
/// Determines the files that belong to the given directory and adds them to the tree.
|
||||
void AddFilesOfDirectory(TreeNode<AssetNode> directory)
|
||||
{
|
||||
// Filter that accepts all files.
|
||||
String filter = scope $"{directory->Path}/*";
|
||||
|
||||
// Buffer used to hold the path of the files iterated below.
|
||||
String filepathBuffer = scope String(256);
|
||||
// Buffer used to hold the file extension of the files iterated below.
|
||||
String extensionBuffer = scope String(16);
|
||||
|
||||
for (var entry in Directory.Enumerate(filter, .Files))
|
||||
{
|
||||
entry.GetFilePath(filepathBuffer..Clear());
|
||||
|
||||
Path.GetExtension(filepathBuffer, .. extensionBuffer..Clear());
|
||||
|
||||
// Ignore meta files.
|
||||
if (extensionBuffer.Equals(AssetFile.ConfigFileExtension, .OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
TreeNode<AssetNode> treeNode = directory.Children.Where(scope (node) => node.Value.Path == filepathBuffer).FirstOrDefault();
|
||||
|
||||
if (treeNode == null)
|
||||
{
|
||||
AssetNode assetNode = new AssetNode();
|
||||
assetNode.Name = new String();
|
||||
Path.GetFileName(filepathBuffer, assetNode.Name);
|
||||
|
||||
filepathBuffer.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
|
||||
assetNode.Path = new String(filepathBuffer);
|
||||
assetNode.IsDirectory = false;
|
||||
|
||||
treeNode = directory.AddChild(assetNode);
|
||||
_pathToAssetNode.Add(assetNode.Path, treeNode);
|
||||
|
||||
//GrabSubAssets(node);
|
||||
HandleFile(treeNode.Value);
|
||||
|
||||
Log.EngineLogger.Trace($"Created file node for: \"{assetNode.Path}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveOrphanedEntries(TreeNode<AssetNode> node)
|
||||
{
|
||||
/// Removes the node and its children from _pathToAssetNode
|
||||
void RemoveSubtree(TreeNode<AssetNode> tree)
|
||||
{
|
||||
_pathToAssetNode.Remove(tree->Path);
|
||||
|
||||
for (var child in tree.Children)
|
||||
{
|
||||
RemoveSubtree(child);
|
||||
}
|
||||
}
|
||||
|
||||
for (TreeNode<AssetNode> child in node.Children)
|
||||
{
|
||||
if (!Directory.Exists(child->Path) && !File.Exists(child->Path))
|
||||
{
|
||||
Log.EngineLogger.Trace($"Removed orphaned node for: \"{child->Path}\"");
|
||||
|
||||
@child.Remove();
|
||||
|
||||
RemoveSubtree(child);
|
||||
|
||||
DeleteTreeAndChildren!(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the given directory to the specified tree.
|
||||
/// Recursively adds all Files and Subdirectories.
|
||||
void AddDirectoryToTree(String path, TreeNode<AssetNode> parentNode)
|
||||
{
|
||||
path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
|
||||
// Try to find the node for the specified path in the given parent
|
||||
TreeNode<AssetNode> treeNode = parentNode.Children.Where(scope (node) => node.Value.Path == path).FirstOrDefault();
|
||||
|
||||
// Create new Node for the Directory, if no TreeNode exists.
|
||||
if (treeNode == null)
|
||||
{
|
||||
AssetNode assetNode = new AssetNode();
|
||||
assetNode.Path = new String(path);
|
||||
assetNode.Name = new String();
|
||||
assetNode.IsDirectory = true;
|
||||
Path.GetFileName(assetNode.Path, assetNode.Name);
|
||||
|
||||
treeNode = parentNode.AddChild(assetNode);
|
||||
_pathToAssetNode.Add(assetNode.Path, treeNode);
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{assetNode.Path}\"");
|
||||
}
|
||||
|
||||
String directoryNameBuffer = scope String(256);
|
||||
|
||||
// Filter that finds all entries of a directory.
|
||||
String filter = scope $"{path}/*";
|
||||
|
||||
for (var directory in Directory.Enumerate(filter, .Directories))
|
||||
{
|
||||
directory.GetFilePath(directoryNameBuffer..Clear());
|
||||
|
||||
AddDirectoryToTree(directoryNameBuffer, treeNode);
|
||||
}
|
||||
|
||||
AddFilesOfDirectory(treeNode);
|
||||
|
||||
RemoveOrphanedEntries(treeNode);
|
||||
}
|
||||
|
||||
String filter = scope $"{ContentDirectory}/*";
|
||||
|
||||
String directoryNameBuffer = scope String(256);
|
||||
|
||||
for (var directory in Directory.Enumerate(filter, .Directories))
|
||||
{
|
||||
directory.GetFilePath(directoryNameBuffer..Clear());
|
||||
|
||||
AddDirectoryToTree(directoryNameBuffer, _assetHierarchy);
|
||||
}
|
||||
|
||||
RemoveOrphanedEntries(_assetHierarchy);
|
||||
|
||||
_fileSystemDirty = false;
|
||||
}
|
||||
|
||||
private void FileContentChanged(StringView fileName)
|
||||
{
|
||||
var fileName;
|
||||
|
||||
// Config files aren't really tracked but changing them effectively changes the corresponding file
|
||||
// so we fire the event for them.
|
||||
if (fileName.EndsWith(AssetFile.ConfigFileExtension))
|
||||
fileName.RemoveFromEnd(AssetFile.ConfigFileExtension.Length);
|
||||
|
||||
String fileNameWithContentRoot = scope .();
|
||||
Path.InternalCombine(fileNameWithContentRoot, _contentDirectory, fileName);
|
||||
|
||||
var nodeResult = GetNodeFromPath(fileNameWithContentRoot);
|
||||
|
||||
TreeNode<AssetNode> node = null;
|
||||
|
||||
if (!(nodeResult case .Ok(out node)))
|
||||
{
|
||||
// This happens, when we create new files.
|
||||
Log.EngineLogger.Trace($"Could not find node for file \"{fileNameWithContentRoot}\"");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't fire event for directories.
|
||||
if (node->IsDirectory)
|
||||
return;
|
||||
|
||||
OnFileContentChanged(node.Value);
|
||||
|
||||
// TODO: Handle file changes (reload asset, etc...)
|
||||
}
|
||||
|
||||
public delegate void FileContentChangedFunc(AssetNode node);
|
||||
|
||||
public Event<FileContentChangedFunc> OnFileContentChanged ~ _.Dispose();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using GlitchyEngine.Content;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace GlitchyEditor.Assets;
|
||||
|
||||
interface IAssetSaver
|
||||
{
|
||||
Result<void> EditorSaveAsset(Stream file, Asset asset, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager);
|
||||
}
|
||||
@@ -7,11 +7,26 @@ using GlitchyEngine;
|
||||
using GlitchyEngine.Renderer;
|
||||
using ImGui;
|
||||
using GlitchyEngine.Math;
|
||||
using System.Diagnostics;
|
||||
using Bon.Integrated;
|
||||
|
||||
namespace GlitchyEditor.Assets;
|
||||
|
||||
class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
{
|
||||
public static bool TryGetValue(Dictionary<String, Variant> parameters, String name, out Variant value)
|
||||
{
|
||||
if (parameters.TryGetValue(name, let param))
|
||||
{
|
||||
value = param;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = ?;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
mixin DropAssetTarget<T>() where T : Asset
|
||||
{
|
||||
Asset asset = null;
|
||||
@@ -83,18 +98,6 @@ class MaterialAssetPropertiesEditor : AssetPropertiesEditor
|
||||
|
||||
private void ShowVariables(Material material, Effect effect)
|
||||
{
|
||||
bool TryGetValue(Dictionary<String, Variant> parameters, String name, out Variant value)
|
||||
{
|
||||
if (parameters.TryGetValue(name, let param))
|
||||
{
|
||||
value = param;
|
||||
return true;
|
||||
}
|
||||
|
||||
value = ?;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||
{
|
||||
@@ -194,16 +197,123 @@ class MaterialAssetLoaderConfig : AssetLoaderConfig
|
||||
|
||||
}
|
||||
|
||||
[BonTarget]
|
||||
public enum VariableValue
|
||||
{
|
||||
case Float(float Value);
|
||||
case Float2(Vector2 Value);
|
||||
case Float3(Vector3 Value);
|
||||
case Float4(Vector4 Value);
|
||||
case Int(int Value);
|
||||
case Int2(Int2 Value);
|
||||
case Int3(Int3 Value);
|
||||
case Int4(Int4 Value);
|
||||
case ColorRGB(ColorRGB Value);
|
||||
case ColorRGBA(ColorRGBA Value);
|
||||
case None;
|
||||
|
||||
/*static this()
|
||||
{
|
||||
gBonEnv.typeHandlers.Add(typeof(Self),
|
||||
((.)new => VariableValueSerialize, (.)new => VariableValueDeserialize));
|
||||
}
|
||||
|
||||
static void VariableValueSerialize(BonWriter writer, ValueView value, BonEnvironment env)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(Self));
|
||||
|
||||
let variableValue = value.Get<Self>();
|
||||
|
||||
writer.Type(variableValue)
|
||||
using (writer.ObjectBlock())
|
||||
{
|
||||
Serialize.Value(writer, nameof(MaterialFile.Effect), materialFile.Effect, env);
|
||||
Serialize.Value(writer, nameof(MaterialFile.Textures), materialFile.Textures, env);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void> VariableValueDeserialize(BonReader reader, ValueView val, BonEnvironment env)
|
||||
{
|
||||
return .Ok;
|
||||
}*/
|
||||
}
|
||||
|
||||
[BonTarget]
|
||||
class MaterialFile
|
||||
{
|
||||
public String Effect ~ delete _;
|
||||
|
||||
public Dictionary<String, String> Textures ~ DeleteDictionaryAndKeysAndValues!(_);
|
||||
//public Dictionary<String, Object> Variables;
|
||||
public Dictionary<String, VariableValue> Variables ~
|
||||
{
|
||||
if (_ != null)
|
||||
{
|
||||
for (var entry in _)
|
||||
{
|
||||
delete entry.key;
|
||||
//delete entry.value;
|
||||
/*if (entry.value.HasValue)
|
||||
entry.value->Dispose();*/
|
||||
}
|
||||
|
||||
delete _;
|
||||
}
|
||||
};
|
||||
|
||||
/*static this()
|
||||
{
|
||||
gBonEnv.typeHandlers.Add(typeof(Self),
|
||||
((.)new => MaterialSerialize, (.)new => MaterialDeserialize));
|
||||
}
|
||||
|
||||
static void MaterialSerialize(BonWriter writer, ValueView value, BonEnvironment env)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(Self));
|
||||
|
||||
let materialFile = value.Get<Self>();
|
||||
|
||||
using (writer.ObjectBlock())
|
||||
{
|
||||
Serialize.Value(writer, nameof(MaterialFile.Effect), materialFile.Effect, env);
|
||||
Serialize.Value(writer, nameof(MaterialFile.Textures), materialFile.Textures, env);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void SerializeVariablesDictionary(BonWriter writer, MaterialFile materialFile, BonEnvironment env)
|
||||
{
|
||||
using (writer.ArrayBlock())
|
||||
{
|
||||
for (let (name, value) in materialFile.Variables)
|
||||
{
|
||||
let keyVal = ValueView(typeof(String), name);
|
||||
Serialize.Value(writer, keyVal, env);
|
||||
writer.Pair();
|
||||
|
||||
ValueView valueVal;// = ValueView(, entriesPtr + (currentIndex * entryStride) + entryValueOffset);
|
||||
switch(value.GetType())
|
||||
{
|
||||
case typeof(ColorRGBA):
|
||||
writer.Identifier("ColorRGBA");
|
||||
default:
|
||||
|
||||
}
|
||||
|
||||
Serialize.Value(writer, valueVal, env);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Result<void> MaterialDeserialize(BonReader reader, ValueView val, BonEnvironment env)
|
||||
{
|
||||
return .Ok;
|
||||
}*/
|
||||
}
|
||||
|
||||
class MaterialAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
class MaterialAssetLoader : IAssetLoader, IAssetSaver //, IReloadingAssetLoader
|
||||
{
|
||||
private static readonly List<StringView> _fileExtensions = new .(){".mat"} ~ delete _;
|
||||
|
||||
@@ -229,6 +339,7 @@ class MaterialAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
if (result case .Err)
|
||||
{
|
||||
Log.EngineLogger.Error("Failed to load material.");
|
||||
Debug.SafeBreak();
|
||||
return null;
|
||||
// TODO: return error material
|
||||
}
|
||||
@@ -243,7 +354,7 @@ class MaterialAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
{
|
||||
if (texture == null)
|
||||
{
|
||||
Log.EngineLogger.Error("Failed to load texture.");
|
||||
Log.EngineLogger.Error($"Failed to load texture \"{textureIdentifier}\".");
|
||||
// TODO: LoadAsset should return an error texture.
|
||||
}
|
||||
|
||||
@@ -253,17 +364,167 @@ class MaterialAssetLoader : IAssetLoader //, IReloadingAssetLoader
|
||||
|
||||
fx.ReleaseRef();
|
||||
|
||||
/*for (let (slotName, textureIdentifier) in materialFile.Variables)
|
||||
for (let (slotName, variableValue) in materialFile.Variables)
|
||||
{
|
||||
if (texture == null)
|
||||
switch (variableValue)
|
||||
{
|
||||
Log.EngineLogger.Error("Failed to load texture.");
|
||||
// TODO: LoadAsset should return an error texture.
|
||||
case .ColorRGBA(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .ColorRGB(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .Float(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .Float2(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .Float3(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .Float4(let value):
|
||||
material.SetVariable(slotName, value);
|
||||
case .None:
|
||||
default:
|
||||
Log.EngineLogger.Error("Errorre");
|
||||
}
|
||||
|
||||
material.SetVariable(slotName, );
|
||||
}*/
|
||||
|
||||
return material; //ModelLoader.LoadMesh(file, subAsset.Value, 0);
|
||||
}
|
||||
|
||||
return material;
|
||||
}
|
||||
|
||||
public Result<void> EditorSaveAsset(Stream file, Asset asset, AssetLoaderConfig config, StringView assetIdentifier, StringView? subAsset, IContentManager contentManager)
|
||||
{
|
||||
Material material = asset as Material;
|
||||
|
||||
if (material == null)
|
||||
{
|
||||
Log.EngineLogger.Error("Asset must be a Material!");
|
||||
return .Err;
|
||||
}
|
||||
|
||||
MaterialFile materialFile = scope .();
|
||||
|
||||
materialFile.Effect = new String(material.Effect.Identifier);
|
||||
materialFile.Textures = new .();
|
||||
materialFile.Variables = new .();
|
||||
|
||||
//material.SetTexture();
|
||||
|
||||
for (let (slotName, textureViewBinding) in material.[Friend]_textures)
|
||||
{
|
||||
//materialFile.Textures.Add(slotName, textureViewBinding.)
|
||||
|
||||
}
|
||||
|
||||
Effect effect = material.Effect;
|
||||
|
||||
if (effect == null)
|
||||
return .Ok;
|
||||
|
||||
for (let (name, arguments) in effect.[Friend]_variableDescriptions)
|
||||
{
|
||||
VariableValue variableValue = .None;
|
||||
//Object variantValue = null;
|
||||
|
||||
let variable = effect.Variables[name];
|
||||
|
||||
bool hasPreviewType = MaterialAssetPropertiesEditor.TryGetValue(arguments, "Type", var previewType);
|
||||
|
||||
if (hasPreviewType && previewType.Get<String>() == "Color")
|
||||
{
|
||||
Log.EngineLogger.AssertDebug(variable.Type == .Float && variable.Rows == 1);
|
||||
|
||||
if (variable.Columns == 3)
|
||||
{
|
||||
material.GetVariable<ColorRGB>(variable.Name, var value);
|
||||
|
||||
value = ColorRGB.LinearToSRGB((ColorRGB)value);
|
||||
|
||||
//variantValue = new box value;
|
||||
variableValue = .ColorRGB(value);
|
||||
}
|
||||
else if (variable.Columns == 4)
|
||||
{
|
||||
material.GetVariable<ColorRGBA>(variable.Name, var value);
|
||||
|
||||
value = ColorRGBA.LinearToSRGB((ColorRGBA)value);
|
||||
|
||||
variableValue = .ColorRGBA(value);
|
||||
//variantValue = new box value;
|
||||
}
|
||||
}
|
||||
else if (variable.Type == .Float && variable.Rows == 1)
|
||||
{
|
||||
switch (variable.Columns)
|
||||
{
|
||||
case 1:
|
||||
material.GetVariable<float>(variable.Name, let value);
|
||||
variableValue = .Float(value);
|
||||
case 2:
|
||||
material.GetVariable<Vector2>(variable.Name, let value);
|
||||
variableValue = .Float2(value);
|
||||
case 3:
|
||||
material.GetVariable<Vector3>(variable.Name, let value);
|
||||
variableValue = .Float3(value);
|
||||
case 4:
|
||||
material.GetVariable<Vector4>(variable.Name, let 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(name, variableValue);
|
||||
}
|
||||
|
||||
String text = scope .();
|
||||
|
||||
gBonEnv.serializeFlags |= .IncludeDefault | .Verbose;
|
||||
|
||||
Bon.Serialize<MaterialFile>(materialFile, text);
|
||||
|
||||
StreamWriter writer = scope .(file, .UTF8, 1024);
|
||||
writer.Write(text);
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
using System;
|
||||
namespace Bon.Integrated;
|
||||
|
||||
extension Serialize
|
||||
{
|
||||
}
|
||||
@@ -6,6 +6,7 @@ using System.Collections;
|
||||
using GlitchyEngine.Renderer;
|
||||
using GlitchyEngine.Math;
|
||||
using GlitchyEngine;
|
||||
using GlitchyEditor.Assets;
|
||||
|
||||
namespace GlitchyEditor.EditWindows
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ class PropertiesWindow : EditorWindow
|
||||
|
||||
private append String _selectedFileName = .();
|
||||
|
||||
private Asset _currentAsset ~ _.ReleaseRef();
|
||||
private Asset _currentAsset ~ _?.ReleaseRef();
|
||||
|
||||
public this(Editor editor)
|
||||
{
|
||||
@@ -104,6 +104,11 @@ class PropertiesWindow : EditorWindow
|
||||
|
||||
_currentPropertiesEditor.ShowEditor();
|
||||
|
||||
if (ImGui.Button("Save Asset"))
|
||||
{
|
||||
_editor.ContentManager.SaveAsset(_currentAsset);
|
||||
}
|
||||
|
||||
if (!assetFile.AssetConfig.Config.Changed)
|
||||
{
|
||||
ImGui.BeginDisabled();
|
||||
|
||||
@@ -73,340 +73,6 @@ namespace GlitchyEditor;
|
||||
}
|
||||
}*/
|
||||
|
||||
public class AssetNode
|
||||
{
|
||||
public String Name ~ delete _;
|
||||
public String Path ~ delete _;
|
||||
|
||||
public bool IsDirectory;
|
||||
|
||||
public AssetFile AssetFile ~ delete _;
|
||||
|
||||
public List<SubAsset> SubAssets ~ {
|
||||
SubAssets?.ClearAndDeleteItems();
|
||||
delete SubAssets;
|
||||
}
|
||||
|
||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
||||
}
|
||||
|
||||
public class SubAsset
|
||||
{
|
||||
public AssetNode Asset;
|
||||
public String Name ~ delete _;
|
||||
//public String AssetInternalPath ~ delete _;
|
||||
|
||||
public Texture2D PreviewImage ~ _?.ReleaseRef();
|
||||
}
|
||||
|
||||
class AssetHierarchy
|
||||
{
|
||||
FileSystemWatcher fsw ~ {
|
||||
_.StopRaisingEvents();
|
||||
delete _;
|
||||
};
|
||||
|
||||
bool _fileSystemDirty = false;
|
||||
|
||||
internal TreeNode<AssetNode> _assetHierarchy = null ~ DeleteTreeAndChildren!(_);
|
||||
private append Dictionary<StringView, TreeNode<AssetNode>> _pathToAssetNode = .();
|
||||
|
||||
private append String _contentDirectory = .();
|
||||
|
||||
private EditorContentManager _contentManager;
|
||||
|
||||
public StringView ContentDirectory
|
||||
{
|
||||
get => _contentDirectory;
|
||||
private set
|
||||
{
|
||||
_contentDirectory.Clear();
|
||||
_contentDirectory.Append(value);
|
||||
Path.Fixup(_contentDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
public this(EditorContentManager contentManager)
|
||||
{
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public void SetContentDirectory(StringView contentDirectory)
|
||||
{
|
||||
ContentDirectory = contentDirectory;
|
||||
|
||||
_fileSystemDirty = true;
|
||||
|
||||
SetupFileSystemWatcher();
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
/// Initializes the FSW for the current ContentDirectory and registers the events.
|
||||
private void SetupFileSystemWatcher()
|
||||
{
|
||||
delete fsw;
|
||||
fsw = new FileSystemWatcher(_contentDirectory);
|
||||
fsw.IncludeSubdirectories = true;
|
||||
|
||||
fsw.OnChanged.Add(new (filename) => {
|
||||
// Note: Gets fired for a directory if a file inside it is created/removed
|
||||
|
||||
Log.EngineLogger.Trace($"File content changed (\"{filename}\")");
|
||||
//_fileSystemDirty = true;
|
||||
|
||||
FileContentChanged(filename);
|
||||
});
|
||||
|
||||
fsw.OnCreated.Add(new (filename) => {
|
||||
Log.EngineLogger.Trace($"File created (\"{filename}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
});
|
||||
|
||||
fsw.OnDeleted.Add(new (filename) => {
|
||||
Log.EngineLogger.Trace($"File deleted (\"{filename}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
});
|
||||
|
||||
fsw.OnRenamed.Add(new (oldName, newName) => {
|
||||
Log.EngineLogger.Trace($"File renamed (From \"{oldName}\" to \"{newName}\")");
|
||||
|
||||
_fileSystemDirty = true;
|
||||
/*String contentFilePath = scope String();
|
||||
|
||||
Path.InternalCombine(contentFilePath, ContentDirectory, oldName);
|
||||
|
||||
//_fileSystemDirty = true;
|
||||
TreeNode<AssetNode> fileNode = GetNodeFromPath(contentFilePath);
|
||||
fileNode->*/
|
||||
});
|
||||
|
||||
fsw.StartRaisingEvents();
|
||||
}
|
||||
|
||||
/// Gets the tree node for the given filePath or null, if the file/directory doesn't exist.
|
||||
/// @param filePath the path for which to return the tree node.
|
||||
/// @remarks Do not hold a reference to the TreeNode because it can become invalid when the file hierarchy changes.
|
||||
public Result<TreeNode<AssetNode>> GetNodeFromPath(StringView filePath)
|
||||
{
|
||||
if (_pathToAssetNode.TryGetValue(filePath, let treeNode))
|
||||
{
|
||||
return treeNode;
|
||||
}
|
||||
|
||||
return .Err;
|
||||
}
|
||||
|
||||
public bool FileExists(StringView filePath)
|
||||
{
|
||||
return _pathToAssetNode.ContainsKey(filePath);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// TODO: do we really need to do this in the update loop?
|
||||
if (_fileSystemDirty)
|
||||
{
|
||||
UpdateFiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Rebuilds the asset file hierarchy.
|
||||
private void UpdateFiles()
|
||||
{
|
||||
Log.EngineLogger.Trace($"Updating asset hierarchy");
|
||||
|
||||
if (_assetHierarchy == null)
|
||||
{
|
||||
// TODO: move to init?
|
||||
|
||||
_assetHierarchy = new TreeNode<AssetNode>(new AssetNode());
|
||||
_assetHierarchy->Path = new String(ContentDirectory);
|
||||
_assetHierarchy->Name = new String("Content");
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{_assetHierarchy->Path}\"");
|
||||
|
||||
_pathToAssetNode.Add(ContentDirectory, _assetHierarchy);
|
||||
}
|
||||
|
||||
void HandleFile(AssetNode node)
|
||||
{
|
||||
String identifier = scope .(node.Path.Length);
|
||||
Path.GetRelativePath(node.Path, _contentDirectory, identifier);
|
||||
|
||||
node.AssetFile = new AssetFile(_contentManager, identifier, node.Path, node.IsDirectory);
|
||||
}
|
||||
|
||||
/// Determines the files that belong to the given directory and adds them to the tree.
|
||||
void AddFilesOfDirectory(TreeNode<AssetNode> directory)
|
||||
{
|
||||
// Filter that accepts all files.
|
||||
String filter = scope $"{directory->Path}/*";
|
||||
|
||||
// Buffer used to hold the path of the files iterated below.
|
||||
String filepathBuffer = scope String(256);
|
||||
// Buffer used to hold the file extension of the files iterated below.
|
||||
String extensionBuffer = scope String(16);
|
||||
|
||||
for (var entry in Directory.Enumerate(filter, .Files))
|
||||
{
|
||||
entry.GetFilePath(filepathBuffer..Clear());
|
||||
|
||||
Path.GetExtension(filepathBuffer, .. extensionBuffer..Clear());
|
||||
|
||||
// Ignore meta files.
|
||||
if (extensionBuffer.Equals(AssetFile.ConfigFileExtension, .OrdinalIgnoreCase))
|
||||
continue;
|
||||
|
||||
TreeNode<AssetNode> treeNode = directory.Children.Where(scope (node) => node.Value.Path == filepathBuffer).FirstOrDefault();
|
||||
|
||||
if (treeNode == null)
|
||||
{
|
||||
AssetNode assetNode = new AssetNode();
|
||||
assetNode.Name = new String();
|
||||
Path.GetFileName(filepathBuffer, assetNode.Name);
|
||||
|
||||
filepathBuffer.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
|
||||
assetNode.Path = new String(filepathBuffer);
|
||||
assetNode.IsDirectory = false;
|
||||
|
||||
treeNode = directory.AddChild(assetNode);
|
||||
_pathToAssetNode.Add(assetNode.Path, treeNode);
|
||||
|
||||
//GrabSubAssets(node);
|
||||
HandleFile(treeNode.Value);
|
||||
|
||||
Log.EngineLogger.Trace($"Created file node for: \"{assetNode.Path}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoveOrphanedEntries(TreeNode<AssetNode> node)
|
||||
{
|
||||
/// Removes the node and its children from _pathToAssetNode
|
||||
void RemoveSubtree(TreeNode<AssetNode> tree)
|
||||
{
|
||||
_pathToAssetNode.Remove(tree->Path);
|
||||
|
||||
for (var child in tree.Children)
|
||||
{
|
||||
RemoveSubtree(child);
|
||||
}
|
||||
}
|
||||
|
||||
for (TreeNode<AssetNode> child in node.Children)
|
||||
{
|
||||
if (!Directory.Exists(child->Path) && !File.Exists(child->Path))
|
||||
{
|
||||
Log.EngineLogger.Trace($"Removed orphaned node for: \"{child->Path}\"");
|
||||
|
||||
@child.Remove();
|
||||
|
||||
RemoveSubtree(child);
|
||||
|
||||
DeleteTreeAndChildren!(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Adds the given directory to the specified tree.
|
||||
/// Recursively adds all Files and Subdirectories.
|
||||
void AddDirectoryToTree(String path, TreeNode<AssetNode> parentNode)
|
||||
{
|
||||
path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
|
||||
// Try to find the node for the specified path in the given parent
|
||||
TreeNode<AssetNode> treeNode = parentNode.Children.Where(scope (node) => node.Value.Path == path).FirstOrDefault();
|
||||
|
||||
// Create new Node for the Directory, if no TreeNode exists.
|
||||
if (treeNode == null)
|
||||
{
|
||||
AssetNode assetNode = new AssetNode();
|
||||
assetNode.Path = new String(path);
|
||||
assetNode.Name = new String();
|
||||
assetNode.IsDirectory = true;
|
||||
Path.GetFileName(assetNode.Path, assetNode.Name);
|
||||
|
||||
treeNode = parentNode.AddChild(assetNode);
|
||||
_pathToAssetNode.Add(assetNode.Path, treeNode);
|
||||
|
||||
Log.EngineLogger.Trace($"Created directory node for: \"{assetNode.Path}\"");
|
||||
}
|
||||
|
||||
String directoryNameBuffer = scope String(256);
|
||||
|
||||
// Filter that finds all entries of a directory.
|
||||
String filter = scope $"{path}/*";
|
||||
|
||||
for (var directory in Directory.Enumerate(filter, .Directories))
|
||||
{
|
||||
directory.GetFilePath(directoryNameBuffer..Clear());
|
||||
|
||||
AddDirectoryToTree(directoryNameBuffer, treeNode);
|
||||
}
|
||||
|
||||
AddFilesOfDirectory(treeNode);
|
||||
|
||||
RemoveOrphanedEntries(treeNode);
|
||||
}
|
||||
|
||||
String filter = scope $"{ContentDirectory}/*";
|
||||
|
||||
String directoryNameBuffer = scope String(256);
|
||||
|
||||
for (var directory in Directory.Enumerate(filter, .Directories))
|
||||
{
|
||||
directory.GetFilePath(directoryNameBuffer..Clear());
|
||||
|
||||
AddDirectoryToTree(directoryNameBuffer, _assetHierarchy);
|
||||
}
|
||||
|
||||
RemoveOrphanedEntries(_assetHierarchy);
|
||||
|
||||
_fileSystemDirty = false;
|
||||
}
|
||||
|
||||
private void FileContentChanged(StringView fileName)
|
||||
{
|
||||
var fileName;
|
||||
|
||||
// Config files aren't really tracked but changing them effectively changes the corresponding file
|
||||
// so we fire the event for them.
|
||||
if (fileName.EndsWith(AssetFile.ConfigFileExtension))
|
||||
fileName.RemoveFromEnd(AssetFile.ConfigFileExtension.Length);
|
||||
|
||||
String fileNameWithContentRoot = scope .();
|
||||
Path.InternalCombine(fileNameWithContentRoot, _contentDirectory, fileName);
|
||||
|
||||
var nodeResult = GetNodeFromPath(fileNameWithContentRoot);
|
||||
|
||||
TreeNode<AssetNode> node = null;
|
||||
|
||||
if (!(nodeResult case .Ok(out node)))
|
||||
{
|
||||
// This happens, when we create new files.
|
||||
Log.EngineLogger.Trace($"Could not find node for file \"{fileNameWithContentRoot}\"");
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't fire event for directories.
|
||||
if (node->IsDirectory)
|
||||
return;
|
||||
|
||||
OnFileContentChanged(node.Value);
|
||||
|
||||
// TODO: Handle file changes (reload asset, etc...)
|
||||
}
|
||||
|
||||
public delegate void FileContentChangedFunc(AssetNode node);
|
||||
|
||||
public Event<FileContentChangedFunc> OnFileContentChanged ~ _.Dispose();
|
||||
}
|
||||
|
||||
class EditorContentManager : IContentManager
|
||||
{
|
||||
private append String _contentDirectory = .();
|
||||
@@ -602,7 +268,6 @@ class EditorContentManager : IContentManager
|
||||
return null;
|
||||
}
|
||||
|
||||
//AssetFile file = scope .(this, filePath, false);
|
||||
AssetFile file = resultNode->Value.AssetFile;
|
||||
|
||||
IAssetLoader assetLoader = null;
|
||||
@@ -628,6 +293,9 @@ class EditorContentManager : IContentManager
|
||||
|
||||
delete stream;
|
||||
|
||||
if (loadedAsset == null)
|
||||
return null;
|
||||
|
||||
//String identifierString = new .(identifier);
|
||||
//_identifiers.Add(identifierString);
|
||||
|
||||
@@ -642,10 +310,91 @@ class EditorContentManager : IContentManager
|
||||
return loadedAsset;
|
||||
}
|
||||
|
||||
/// Saves the asset.
|
||||
public Result<void> SaveAsset(Asset asset)
|
||||
{
|
||||
// Find subasset name
|
||||
int poundIndex = asset.Identifier.IndexOf('#');
|
||||
|
||||
StringView resourceName = poundIndex == -1 ? asset.Identifier : asset.Identifier.Substring(0, poundIndex);
|
||||
StringView? subassetName = asset.Identifier.Substring(poundIndex + 1);
|
||||
|
||||
String filePath = scope String(resourceName.Length + _contentDirectory.Length + 2);
|
||||
Path.Combine(filePath, _contentDirectory, resourceName);
|
||||
|
||||
Path.Fixup(filePath);
|
||||
|
||||
//filePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
|
||||
|
||||
TreeNode<AssetNode> assetNode = Try!(AssetHierarchy.GetNodeFromPath(filePath));
|
||||
|
||||
AssetFile file = assetNode->AssetFile;
|
||||
|
||||
IAssetLoader assetLoader = null;
|
||||
|
||||
String loaderTypeName = scope .(128);
|
||||
|
||||
for (IAssetLoader loader in _assetLoaders)
|
||||
{
|
||||
loader.GetType().GetName(loaderTypeName..Clear());
|
||||
|
||||
if (loaderTypeName == file.AssetConfig.AssetLoader)
|
||||
{
|
||||
assetLoader = loader;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IAssetSaver assetSaver = assetLoader as IAssetSaver;
|
||||
|
||||
if (assetSaver == null)
|
||||
{
|
||||
Log.EngineLogger.Error("The asset loader can't save!");
|
||||
return .Err;
|
||||
}
|
||||
|
||||
Stream stream = OpenStream(filePath, false, true);
|
||||
|
||||
assetSaver.EditorSaveAsset(stream, asset, file.AssetConfig.Config, resourceName, subassetName, this);
|
||||
|
||||
delete stream;
|
||||
|
||||
return .Ok;
|
||||
}
|
||||
|
||||
private Stream OpenStream(StringView assetIdentifier, bool openOnly, bool truncate = false)
|
||||
{
|
||||
var assetIdentifier;
|
||||
|
||||
if (!assetIdentifier.StartsWith(_contentDirectory))
|
||||
{
|
||||
String filePath = scope:: String(assetIdentifier.Length + _contentDirectory.Length + 2);
|
||||
Path.Combine(filePath, _contentDirectory, assetIdentifier);
|
||||
|
||||
assetIdentifier = filePath;
|
||||
}
|
||||
|
||||
FileStream fs = new FileStream();
|
||||
|
||||
FileMode fileMode = openOnly ? FileMode.Open : FileMode.OpenOrCreate;
|
||||
|
||||
if (truncate)
|
||||
fileMode |= .Truncate;
|
||||
|
||||
var result = fs.Open(assetIdentifier, fileMode, openOnly ? .Read : .ReadWrite, .ReadWrite);
|
||||
|
||||
if (result case .Err)
|
||||
return null;
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
// TODO: probably not needed
|
||||
public Stream GetStream(StringView assetIdentifier)
|
||||
{
|
||||
var assetIdentifier;
|
||||
return OpenStream(assetIdentifier, true);
|
||||
|
||||
/*var assetIdentifier;
|
||||
|
||||
if (!assetIdentifier.StartsWith(_contentDirectory))
|
||||
{
|
||||
@@ -661,7 +410,7 @@ class EditorContentManager : IContentManager
|
||||
if (result case .Err)
|
||||
return null;
|
||||
|
||||
return fs;
|
||||
return fs;*/
|
||||
}
|
||||
|
||||
public void ManageAsset(Asset asset)
|
||||
|
||||
@@ -46,7 +46,7 @@ class Asset : RefCounter
|
||||
_contentManager?.UnmanageAsset(this);
|
||||
}
|
||||
|
||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment)
|
||||
static void AssetSerialize(BonWriter writer, ValueView value, BonEnvironment environment, SerializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(Asset));
|
||||
|
||||
@@ -54,7 +54,7 @@ class Asset : RefCounter
|
||||
writer.String(identifier);
|
||||
}
|
||||
|
||||
static Result<void> AssetDeserialize(BonReader reader, ValueView value, BonEnvironment environment)//, DeserializeFieldState state)
|
||||
static Result<void> AssetDeserialize(BonReader reader, ValueView value, BonEnvironment environment, DeserializeValueState state)
|
||||
{
|
||||
Log.EngineLogger.Assert(value.type == typeof(Asset));
|
||||
|
||||
|
||||
@@ -36,14 +36,14 @@ namespace GlitchyEngine.Core
|
||||
return (int)_uuid;
|
||||
}
|
||||
|
||||
static void Serialize(BonWriter writer, ValueView val, BonEnvironment env)
|
||||
static void Serialize(BonWriter writer, ValueView val, BonEnvironment env, SerializeValueState state)
|
||||
{
|
||||
UUID uuid = *(UUID*)val.dataPtr;
|
||||
|
||||
Bon.Integrated.Serialize.[Friend]Integer(typeof(uint64), writer, ValueView(typeof(uint64), &uuid._uuid));
|
||||
}
|
||||
|
||||
public static Result<void> Deserialize(BonReader reader, ValueView val, BonEnvironment env)
|
||||
public static Result<void> Deserialize(BonReader reader, ValueView val, BonEnvironment env, DeserializeValueState state)
|
||||
{
|
||||
Bon.Integrated.Deserialize.[Friend]Integer!(typeof(uint64), reader, val);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace GlitchyEngine.World
|
||||
|
||||
String buffer = scope String();
|
||||
let writer = scope BonWriter(buffer, true);
|
||||
Serialize.Start(writer);
|
||||
var length = Serialize.Start(writer);
|
||||
|
||||
gBonEnv.serializeFlags |= .IncludeDefault | .Verbose;
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace GlitchyEngine.World
|
||||
writer.EntryEnd();
|
||||
}
|
||||
|
||||
Serialize.End(writer);
|
||||
Serialize.End(writer, length);
|
||||
|
||||
String targetDirectory = Path.GetDirectoryPath(filePath, .. scope String());
|
||||
Directory.CreateDirectory(targetDirectory);
|
||||
|
||||
Vendored
+1
-1
Submodule GlitchyEngine/vendor/bon updated: 928cfa14ea...0c80e365cd
Reference in New Issue
Block a user