diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml
index 3d99537ba..3bb5242fe 100644
--- a/.github/workflows/build_linux.yml
+++ b/.github/workflows/build_linux.yml
@@ -8,15 +8,18 @@ jobs:
name: Editor (Linux, Development x64)
runs-on: "ubuntu-20.04"
steps:
- - name: Install dependencies
- run: |
- sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Checkout repo
uses: actions/checkout@v2
- name: Checkout LFS
run: |
git lfs version
git lfs pull
+ - name: Install dependencies
+ run: |
+ sudo rm -f /etc/apt/sources.list.d/*
+ sudo cp -f .github/workflows/build_linux_sources.list /etc/apt/sources.list
+ sudo apt-get update
+ sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
- name: Build
run: |
./Development/Scripts/Linux/CallBuildTool.sh -build -log -arch=x64 -platform=Linux -configuration=Development -buildtargets=FlaxEditor
diff --git a/.github/workflows/build_linux_sources.list b/.github/workflows/build_linux_sources.list
new file mode 100644
index 000000000..4d8f94f35
--- /dev/null
+++ b/.github/workflows/build_linux_sources.list
@@ -0,0 +1,4 @@
+deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-security main restricted universe multiverse
+deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted universe multiverse
diff --git a/Content/Editor/IconsAtlas.flax b/Content/Editor/IconsAtlas.flax
index 9dda6fec2..13af92065 100644
--- a/Content/Editor/IconsAtlas.flax
+++ b/Content/Editor/IconsAtlas.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:51daf141b7f0d7faf83bb42eceebf9c5442a2f101d02e352215b9684842b5fc7
-size 5636265
+oid sha256:de930eef22208b95882bc9f870063e339672b577d381bcfa6603f0be45c814c5
+size 5610110
diff --git a/Content/Editor/Scripting/CppAssetTemplate.h b/Content/Editor/Scripting/CppAssetTemplate.h
new file mode 100644
index 000000000..ddd8109c7
--- /dev/null
+++ b/Content/Editor/Scripting/CppAssetTemplate.h
@@ -0,0 +1,23 @@
+%copyright%
+#pragma once
+
+#include "Engine/Core/ISerializable.h"
+#include "Engine/Core/Types/BaseTypes.h"
+#include "Engine/Content/Assets/Model.h"
+#include "Engine/Scripting/ScriptingType.h"
+
+///
+/// %class% Json Asset.
+///
+API_CLASS() class %module%%class% : public ISerializable
+{
+ API_AUTO_SERIALIZATION();
+ DECLARE_SCRIPTING_TYPE_NO_SPAWN(%class%);
+public:
+ // Custom float value.
+ API_FIELD(Attributes = "Range(0, 20), EditorOrder(0), EditorDisplay(\"Data\")")
+ float FloatValue = 20.0f;
+ // Custom vector data.
+ API_FIELD(Attributes = "EditorOrder(1), EditorDisplay(\"Data\")")
+ Vector3 Vector3Value = Vector3(0.1f);
+};
diff --git a/Content/Editor/Scripting/CppStaticClassTemplate.cpp b/Content/Editor/Scripting/CppStaticClassTemplate.cpp
new file mode 100644
index 000000000..08ffb9348
--- /dev/null
+++ b/Content/Editor/Scripting/CppStaticClassTemplate.cpp
@@ -0,0 +1,8 @@
+%copyright%
+#include "%filename%.h"
+#include "Engine/Core/Log.h"
+
+void %class%::RunNativeAction(Vector4 data)
+{
+ LOG(Warning, "Data in RunNativeAction: {0}", data);
+}
diff --git a/Content/Editor/Scripting/CppStaticClassTemplate.h b/Content/Editor/Scripting/CppStaticClassTemplate.h
new file mode 100644
index 000000000..8b235695f
--- /dev/null
+++ b/Content/Editor/Scripting/CppStaticClassTemplate.h
@@ -0,0 +1,20 @@
+%copyright%
+#pragma once
+
+#include "Engine/Scripting/Script.h"
+#include "Engine/Core/Math/Vector4.h"
+
+///
+/// %class% Function Library
+///
+API_CLASS(Static) class %module%%class%
+{
+ DECLARE_SCRIPTING_TYPE_MINIMAL(%class%);
+public:
+
+ ///
+ /// Logs the function parameter natively.
+ ///
+ /// Data to pass to native code
+ API_FUNCTION() static void RunNativeAction(Vector4 data);
+};
diff --git a/Content/Editor/Scripting/ScriptTemplate.cs b/Content/Editor/Scripting/ScriptTemplate.cs
index c9ae5068e..2a150306d 100644
--- a/Content/Editor/Scripting/ScriptTemplate.cs
+++ b/Content/Editor/Scripting/ScriptTemplate.cs
@@ -4,23 +4,30 @@ using FlaxEngine;
namespace %namespace%
{
+ ///
+ /// %class% Script.
+ ///
public class %class% : Script
{
+ ///
public override void OnStart()
{
// Here you can add code that needs to be called when script is created, just before the first game update
}
-
+
+ ///
public override void OnEnable()
{
// Here you can add code that needs to be called when script is enabled (eg. register for events)
}
+ ///
public override void OnDisable()
{
// Here you can add code that needs to be called when script is disabled (eg. unregister from events)
}
+ ///
public override void OnUpdate()
{
// Here you can add code that needs to be called every frame
diff --git a/Content/Shaders/BitonicSort.flax b/Content/Shaders/BitonicSort.flax
index 1d5b8a581..c9dd81dc9 100644
--- a/Content/Shaders/BitonicSort.flax
+++ b/Content/Shaders/BitonicSort.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:f46a61cf8d5183230176e661a51208bfeece16cc7238655f406288ff448af64e
-size 6721
+oid sha256:0c780dc1881ef96dece237bde3e87fca3c9e4e542d89ebde7c9308f00f81c6a9
+size 6808
diff --git a/Content/Shaders/DepthOfField.flax b/Content/Shaders/DepthOfField.flax
index a84047429..6c4d9daec 100644
--- a/Content/Shaders/DepthOfField.flax
+++ b/Content/Shaders/DepthOfField.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:92355644db4cdfd96250b779a87385e6805d01ce084801b3a4be704f026e9bca
-size 21025
+oid sha256:d8b69fce536cb27d497f6ff91f8adff3fbeaa9a704ced1b3271f4d621c195d53
+size 21054
diff --git a/Content/Shaders/EyeAdaptation.flax b/Content/Shaders/EyeAdaptation.flax
index 9c538e798..93e17c1a2 100644
--- a/Content/Shaders/EyeAdaptation.flax
+++ b/Content/Shaders/EyeAdaptation.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c12b7b43743e4e609a4155d7a4117421298d679d07548ffa48a386da496556b0
-size 4605
+oid sha256:f0d2b41560554e53692958ddea4cb53a082a7fbe88d7cb99eeccd095c45f631a
+size 4600
diff --git a/Content/Shaders/GUI.flax b/Content/Shaders/GUI.flax
index 73fd80725..0e9077247 100644
--- a/Content/Shaders/GUI.flax
+++ b/Content/Shaders/GUI.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:ea8cffddde04c7f3829ce0bd0cb61deecb50a9ac954c552cddb72d182538d605
-size 5108
+oid sha256:aae706e79bbc4eb9508da338a3ba2b4300f012771bac3c1a43835fd41ad7282a
+size 5111
diff --git a/Content/Shaders/VolumetricFog.flax b/Content/Shaders/VolumetricFog.flax
index 118e46c91..19420d9ad 100644
--- a/Content/Shaders/VolumetricFog.flax
+++ b/Content/Shaders/VolumetricFog.flax
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:81de76f651892a4d410c4624de3cab685d29b6711938c04325dac776588e3ec9
-size 14293
+oid sha256:2b71f70eab5a3139707a624ec2ea796e83114d3cc5351c9648921e13bffa2386
+size 14288
diff --git a/Development/Documentation/mono.md b/Development/Documentation/mono.md
index bbde0cd56..d292ebb3d 100644
--- a/Development/Documentation/mono.md
+++ b/Development/Documentation/mono.md
@@ -5,6 +5,7 @@ Custom fork: [https://github.com/FlaxEngine/mono](https://github.com/FlaxEngine/
### Notes
Some useful notes and tips for devs:
+* Use `-monolog` to print Mono logs to Flax logs
* When working with mono fork set `localRepoPath` to local repo location in `Source\Tools\Flax.Build\Deps\Dependencies\mono.cs`
* To update mono deps when developing/updating use `.\Development\Scripts\Windows\CallBuildTool.bat -log -ReBuildDeps -verbose -depsToBuild=mono -platform=Windows`, then build engine and run it
* `MONO_GC_DEBUG=check-remset-consistency` - it will do additional checks at each collection to see if there are any missing write barriers
diff --git a/Source/Editor/Analytics/EditorAnalytics.cpp b/Source/Editor/Analytics/EditorAnalytics.cpp
index 3f067719e..c2a293c15 100644
--- a/Source/Editor/Analytics/EditorAnalytics.cpp
+++ b/Source/Editor/Analytics/EditorAnalytics.cpp
@@ -10,6 +10,7 @@
#include "Editor/Editor.h"
#include "Editor/ProjectInfo.h"
#include "Engine/Engine/EngineService.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Utilities/StringConverter.h"
#include "FlaxEngine.Gen.h"
diff --git a/Source/Editor/Content/Create/SettingsCreateEntry.cs b/Source/Editor/Content/Create/SettingsCreateEntry.cs
index 0cbda246b..974de76cc 100644
--- a/Source/Editor/Content/Create/SettingsCreateEntry.cs
+++ b/Source/Editor/Content/Create/SettingsCreateEntry.cs
@@ -53,6 +53,11 @@ namespace FlaxEditor.Content.Create
///
NavigationSettings,
+ ///
+ /// The localization settings.
+ ///
+ LocalizationSettings,
+
///
/// The build settings.
///
@@ -108,6 +113,7 @@ namespace FlaxEditor.Content.Create
typeof(PhysicsSettings),
typeof(GraphicsSettings),
typeof(NavigationSettings),
+ typeof(LocalizationSettings),
typeof(BuildSettings),
typeof(InputSettings),
typeof(WindowsPlatformSettings),
diff --git a/Source/Editor/Content/Import/ImportFileEntry.cs b/Source/Editor/Content/Import/ImportFileEntry.cs
index 80cab94d3..5d21d3726 100644
--- a/Source/Editor/Content/Import/ImportFileEntry.cs
+++ b/Source/Editor/Content/Import/ImportFileEntry.cs
@@ -116,8 +116,7 @@ namespace FlaxEditor.Content.Import
if (FileTypes.TryGetValue(extension, out ImportFileEntryHandler createDelegate))
return createDelegate(ref request);
- // Use default type
- return request.IsBinaryAsset ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
+ return request.IsInBuilt ? new AssetImportEntry(ref request) : new ImportFileEntry(ref request);
}
internal static void RegisterDefaultTypes()
diff --git a/Source/Editor/Content/Import/Request.cs b/Source/Editor/Content/Import/Request.cs
index b9da30afb..d38b0bfd0 100644
--- a/Source/Editor/Content/Import/Request.cs
+++ b/Source/Editor/Content/Import/Request.cs
@@ -21,9 +21,9 @@ namespace FlaxEditor.Content.Import
public string OutputPath;
///
- /// Flag set to true for binary assets handled by the engine internally.
+ /// Flag set to true for the assets handled by the engine internally.
///
- public bool IsBinaryAsset;
+ public bool IsInBuilt;
///
/// Flag used to skip showing import settings dialog to used. Can be used for importing assets from code by plugins.
diff --git a/Source/Editor/Content/Import/TextureImportEntry.cs b/Source/Editor/Content/Import/TextureImportEntry.cs
index c276dce1b..db1e3ae8c 100644
--- a/Source/Editor/Content/Import/TextureImportEntry.cs
+++ b/Source/Editor/Content/Import/TextureImportEntry.cs
@@ -483,7 +483,9 @@ namespace FlaxEditor.Content.Import
{
if (settings is TextureImportSettings o)
{
+ var sprites = o.Sprites ?? _settings.Sprites; // Preserve sprites if not specified to override
_settings = o;
+ _settings.Sprites = sprites;
return true;
}
return false;
diff --git a/Source/Editor/Content/Items/CSharpScriptItem.cs b/Source/Editor/Content/Items/CSharpScriptItem.cs
index 6160de2bb..332b48558 100644
--- a/Source/Editor/Content/Items/CSharpScriptItem.cs
+++ b/Source/Editor/Content/Items/CSharpScriptItem.cs
@@ -20,6 +20,6 @@ namespace FlaxEditor.Content
}
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CSharpScript128;
}
}
diff --git a/Source/Editor/Content/Items/ContentFolder.cs b/Source/Editor/Content/Items/ContentFolder.cs
index 8ae934b78..8c7e52b2c 100644
--- a/Source/Editor/Content/Items/ContentFolder.cs
+++ b/Source/Editor/Content/Items/ContentFolder.cs
@@ -121,7 +121,7 @@ namespace FlaxEditor.Content
public override bool Exists => Directory.Exists(Path);
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Folder128;
///
internal override void UpdatePath(string value)
diff --git a/Source/Editor/Content/Items/ContentItem.cs b/Source/Editor/Content/Items/ContentItem.cs
index 2e75de940..9813cd44e 100644
--- a/Source/Editor/Content/Items/ContentItem.cs
+++ b/Source/Editor/Content/Items/ContentItem.cs
@@ -455,7 +455,7 @@ namespace FlaxEditor.Content
const float thumbnailInShadowSize = 50.0f;
var shadowRect = rectangle.MakeExpanded((DefaultThumbnailSize - thumbnailInShadowSize) * rectangle.Width / DefaultThumbnailSize * 1.3f);
if (!_shadowIcon.IsValid)
- _shadowIcon = Editor.Instance.Icons.AssetShadow;
+ _shadowIcon = Editor.Instance.Icons.AssetShadow128;
Render2D.DrawSprite(_shadowIcon, shadowRect);
}
diff --git a/Source/Editor/Content/Items/CppScriptItem.cs b/Source/Editor/Content/Items/CppScriptItem.cs
index 1f7bc9f19..1ffead58c 100644
--- a/Source/Editor/Content/Items/CppScriptItem.cs
+++ b/Source/Editor/Content/Items/CppScriptItem.cs
@@ -20,6 +20,6 @@ namespace FlaxEditor.Content
}
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CppScript64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CPPScript128;
}
}
diff --git a/Source/Editor/Content/Items/FileItem.cs b/Source/Editor/Content/Items/FileItem.cs
index 7a3d0fa65..a078178d8 100644
--- a/Source/Editor/Content/Items/FileItem.cs
+++ b/Source/Editor/Content/Items/FileItem.cs
@@ -26,6 +26,6 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
}
}
diff --git a/Source/Editor/Content/Items/JsonAssetItem.cs b/Source/Editor/Content/Items/JsonAssetItem.cs
index 6e32ad49a..1c9232c9c 100644
--- a/Source/Editor/Content/Items/JsonAssetItem.cs
+++ b/Source/Editor/Content/Items/JsonAssetItem.cs
@@ -11,6 +11,8 @@ namespace FlaxEditor.Content
///
public class JsonAssetItem : AssetItem
{
+ private readonly SpriteHandle _thumbnail;
+
///
/// Initializes a new instance of the class.
///
@@ -20,13 +22,27 @@ namespace FlaxEditor.Content
public JsonAssetItem(string path, Guid id, string typeName)
: base(path, typeName, ref id)
{
+ _thumbnail = Editor.Instance.Icons.Document128;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The path.
+ /// The identifier.
+ /// Name of the resource type.
+ /// Asset icon.
+ public JsonAssetItem(string path, Guid id, string typeName, SpriteHandle thumbnail)
+ : base(path, typeName, ref id)
+ {
+ _thumbnail = thumbnail;
}
///
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Json;
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
+ public override SpriteHandle DefaultThumbnail => _thumbnail;
///
protected override bool DrawShadow => false;
diff --git a/Source/Editor/Content/Items/NewItem.cs b/Source/Editor/Content/Items/NewItem.cs
index da06c6bfd..366e07df8 100644
--- a/Source/Editor/Content/Items/NewItem.cs
+++ b/Source/Editor/Content/Items/NewItem.cs
@@ -40,7 +40,7 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Other;
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
///
protected override bool DrawShadow => true;
diff --git a/Source/Editor/Content/Items/SceneItem.cs b/Source/Editor/Content/Items/SceneItem.cs
index 190fe9807..15b79e96b 100644
--- a/Source/Editor/Content/Items/SceneItem.cs
+++ b/Source/Editor/Content/Items/SceneItem.cs
@@ -28,7 +28,7 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Scene;
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Scene128;
///
public override bool IsOfType(Type type)
diff --git a/Source/Editor/Content/Items/ShaderSourceItem.cs b/Source/Editor/Content/Items/ShaderSourceItem.cs
index 77cd6d6ee..7ae04257b 100644
--- a/Source/Editor/Content/Items/ShaderSourceItem.cs
+++ b/Source/Editor/Content/Items/ShaderSourceItem.cs
@@ -27,6 +27,6 @@ namespace FlaxEditor.Content
public override ContentItemSearchFilter SearchFilter => ContentItemSearchFilter.Shader;
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
}
}
diff --git a/Source/Editor/Content/Items/VisualScriptItem.cs b/Source/Editor/Content/Items/VisualScriptItem.cs
index e2a390b60..04311644b 100644
--- a/Source/Editor/Content/Items/VisualScriptItem.cs
+++ b/Source/Editor/Content/Items/VisualScriptItem.cs
@@ -539,7 +539,7 @@ namespace FlaxEditor.Content
}
///
- public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.CodeScript64;
+ public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128;
///
protected override bool DrawShadow => false;
diff --git a/Source/Editor/Content/PreviewsCache.cpp b/Source/Editor/Content/PreviewsCache.cpp
index c51e8cabb..c89b00004 100644
--- a/Source/Editor/Content/PreviewsCache.cpp
+++ b/Source/Editor/Content/PreviewsCache.cpp
@@ -76,7 +76,7 @@ void PreviewsCache::FlushTask::OnEnd()
ThreadPoolTask::OnEnd();
}
-REGISTER_BINARY_ASSET(PreviewsCache, "FlaxEditor.PreviewsCache", ::New(), false);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(PreviewsCache, "FlaxEditor.PreviewsCache", TextureAssetUpgrader, false);
PreviewsCache::PreviewsCache(const SpawnParams& params, const AssetInfo* info)
: SpriteAtlas(params, info)
diff --git a/Source/Editor/Content/Proxy/ContentProxy.cs b/Source/Editor/Content/Proxy/ContentProxy.cs
index 0948ef5e8..afb5c11fb 100644
--- a/Source/Editor/Content/Proxy/ContentProxy.cs
+++ b/Source/Editor/Content/Proxy/ContentProxy.cs
@@ -73,6 +73,16 @@ namespace FlaxEditor.Content
throw new NotImplementedException();
}
+ ///
+ /// Determines whether the specified filename is valid for this proxy.
+ ///
+ /// The filename.
+ /// true if the filename is valid, otherwise false.
+ public virtual bool IsFileNameValid(string filename)
+ {
+ return true;
+ }
+
///
/// Determines whether this proxy can create items in the specified target location.
///
diff --git a/Source/Editor/Content/Proxy/CppProxy.cs b/Source/Editor/Content/Proxy/CppProxy.cs
new file mode 100644
index 000000000..9ced48653
--- /dev/null
+++ b/Source/Editor/Content/Proxy/CppProxy.cs
@@ -0,0 +1,134 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System;
+using System.IO;
+using System.Text;
+using FlaxEditor.Content.Settings;
+using FlaxEngine;
+
+namespace FlaxEditor.Content
+{
+ ///
+ /// Context proxy object for C++ files.
+ ///
+ ///
+ public abstract class CppProxy : ScriptProxy
+ {
+ ///
+ /// Gets the paths for header and source files to format.
+ ///
+ /// The header template path.
+ /// The source template path.
+ protected abstract void GetTemplatePaths(out string headerTemplate, out string sourceTemplate);
+
+ ///
+ public override bool IsProxyFor(ContentItem item)
+ {
+ return false;
+ }
+
+ ///
+ public override void Create(string outputPath, object arg)
+ {
+ // Find the module that this script is being added (based on the path)
+ var module = string.Empty;
+ var project = TryGetProjectAtFolder(outputPath, out var moduleName);
+ if (project != null)
+ {
+ module = moduleName.ToUpperInvariant() + "_API ";
+ }
+
+ var gameSettings = GameSettings.Load();
+ var scriptName = ScriptItem.CreateScriptName(outputPath);
+ var filename = Path.GetFileNameWithoutExtension(outputPath);
+ var copyrightComment = string.IsNullOrEmpty(gameSettings.CopyrightNotice) ? string.Empty : string.Format("// {0}{1}{1}", gameSettings.CopyrightNotice, Environment.NewLine);
+
+ GetTemplatePaths(out var headerTemplatePath, out var sourceTemplatePath);
+ if (headerTemplatePath != null)
+ {
+ var headerTemplate = File.ReadAllText(headerTemplatePath);
+ headerTemplate = headerTemplate.Replace("%copyright%", copyrightComment);
+ headerTemplate = headerTemplate.Replace("%class%", scriptName);
+ headerTemplate = headerTemplate.Replace("%module%", module);
+ headerTemplate = headerTemplate.Replace("%filename%", filename);
+ File.WriteAllText(Path.ChangeExtension(outputPath, ".h"), headerTemplate, Encoding.UTF8);
+ }
+ if (sourceTemplatePath != null)
+ {
+ var sourceTemplate = File.ReadAllText(sourceTemplatePath);
+ sourceTemplate = sourceTemplate.Replace("%copyright%", copyrightComment);
+ sourceTemplate = sourceTemplate.Replace("%class%", scriptName);
+ sourceTemplate = sourceTemplate.Replace("%module%", module);
+ sourceTemplate = sourceTemplate.Replace("%filename%", filename);
+ File.WriteAllText(outputPath, sourceTemplate, Encoding.UTF8);
+ }
+ }
+
+ ///
+ public override string FileExtension => "cpp";
+
+ ///
+ public override Color AccentColor => Color.FromRGB(0x9c1c9c);
+ }
+
+ ///
+ /// Context proxy object for C++ script files.
+ ///
+ ///
+ public class CppScriptProxy : CppProxy
+ {
+ ///
+ public override string Name => "C++ Script";
+
+ ///
+ public override bool IsProxyFor(ContentItem item)
+ {
+ return item is CppScriptItem;
+ }
+
+ ///
+ protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
+ {
+ headerTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.h");
+ sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.cpp");
+ }
+ }
+
+ ///
+ /// Context proxy object for C++ Json Asset files.
+ ///
+ ///
+ public class CppStaticClassProxy : CppProxy
+ {
+ ///
+ public override string Name => "C++ Function Library";
+
+ ///
+ protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
+ {
+ headerTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppStaticClassTemplate.h");
+ sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppStaticClassTemplate.cpp");
+ }
+ }
+
+ ///
+ /// Context proxy object for C++ Json Asset files.
+ ///
+ ///
+ public class CppAssetProxy : CppProxy
+ {
+ ///
+ public override string Name => "C++ Json Asset";
+
+ ///
+ protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
+ {
+ headerTemplate = null;
+ sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppAssetTemplate.h");
+ //sourceTemplate = StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/CppAssetTemplate.cpp");
+ }
+
+ ///
+ public override string FileExtension => "h";
+ }
+}
diff --git a/Source/Editor/Content/Proxy/CppScriptProxy.cs b/Source/Editor/Content/Proxy/CppScriptProxy.cs
deleted file mode 100644
index 8bad93021..000000000
--- a/Source/Editor/Content/Proxy/CppScriptProxy.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
-
-using System;
-using System.IO;
-using System.Text;
-using FlaxEditor.Content.Settings;
-using FlaxEngine;
-
-namespace FlaxEditor.Content
-{
- ///
- /// Context proxy object for C++ script files.
- ///
- ///
- public class CppScriptProxy : ScriptProxy
- {
- ///
- public override string Name => "C++ Script";
-
- ///
- public override bool IsProxyFor(ContentItem item)
- {
- return item is CppScriptItem;
- }
-
- ///
- public override void Create(string outputPath, object arg)
- {
- // Load templates
- var headerTemplate = File.ReadAllText(StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.h"));
- var sourceTemplate = File.ReadAllText(StringUtils.CombinePaths(Globals.EngineContentFolder, "Editor/Scripting/ScriptTemplate.cpp"));
-
- // Find the module that this script is being added (based on the path)
- var module = string.Empty;
- var project = TryGetProjectAtFolder(outputPath, out var moduleName);
- if (project != null)
- {
- module = moduleName.ToUpperInvariant() + "_API ";
- }
-
- // Format
- var gameSettings = GameSettings.Load();
- var scriptName = ScriptItem.CreateScriptName(outputPath);
- var filename = Path.GetFileNameWithoutExtension(outputPath);
- var copyrightComment = string.IsNullOrEmpty(gameSettings.CopyrightNotice) ? string.Empty : string.Format("// {0}{1}{1}", gameSettings.CopyrightNotice, Environment.NewLine);
- headerTemplate = headerTemplate.Replace("%copyright%", copyrightComment);
- headerTemplate = headerTemplate.Replace("%class%", scriptName);
- headerTemplate = headerTemplate.Replace("%module%", module);
- sourceTemplate = sourceTemplate.Replace("%filename%", filename);
- sourceTemplate = sourceTemplate.Replace("%copyright%", copyrightComment);
- sourceTemplate = sourceTemplate.Replace("%class%", scriptName);
- sourceTemplate = sourceTemplate.Replace("%filename%", filename);
-
- // Save
- File.WriteAllText(Path.ChangeExtension(outputPath, ".h"), headerTemplate, Encoding.UTF8);
- File.WriteAllText(outputPath, sourceTemplate, Encoding.UTF8);
- }
-
- ///
- public override string FileExtension => "cpp";
-
- ///
- public override Color AccentColor => Color.FromRGB(0x9c1c9c);
- }
-}
diff --git a/Source/Editor/Content/Proxy/JsonAssetProxy.cs b/Source/Editor/Content/Proxy/JsonAssetProxy.cs
index 25155d39d..41cc06ee1 100644
--- a/Source/Editor/Content/Proxy/JsonAssetProxy.cs
+++ b/Source/Editor/Content/Proxy/JsonAssetProxy.cs
@@ -2,7 +2,6 @@
using System;
using FlaxEditor.Content.Create;
-using FlaxEditor.Content.Settings;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.Windows;
@@ -45,18 +44,12 @@ namespace FlaxEditor.Content
///
public override bool IsProxyFor(ContentItem item)
{
- return item is JsonAssetItem;
+ return item is JsonAssetItem json && json.TypeName == TypeName;
}
///
public override Color AccentColor => Color.FromRGB(0xd14f67);
- ///
- public override bool AcceptsAsset(string typeName, string path)
- {
- return typeName == TypeName && base.AcceptsAsset(typeName, path);
- }
-
///
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
{
@@ -143,6 +136,12 @@ namespace FlaxEditor.Content
return path.EndsWith(FileExtension, StringComparison.OrdinalIgnoreCase);
}
+ ///
+ public override bool IsProxyFor(ContentItem item)
+ {
+ return item is JsonAssetItem;
+ }
+
///
public override bool CanCreate(ContentFolder targetLocation)
{
diff --git a/Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs b/Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
new file mode 100644
index 000000000..2e15f9543
--- /dev/null
+++ b/Source/Editor/Content/Proxy/LocalizedStringTableProxy.cs
@@ -0,0 +1,24 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using FlaxEditor.Windows;
+using FlaxEditor.Windows.Assets;
+using FlaxEngine;
+
+namespace FlaxEditor.Content
+{
+ ///
+ /// proxy.
+ ///
+ ///
+ public class LocalizedStringTableProxy : JsonAssetProxy
+ {
+ ///
+ public override EditorWindow Open(Editor editor, ContentItem item)
+ {
+ return new LocalizedStringTableWindow(editor, (JsonAssetItem)item);
+ }
+
+ ///
+ public override string TypeName => "FlaxEngine.LocalizedStringTable";
+ }
+}
diff --git a/Source/Editor/Content/Proxy/ScriptProxy.cs b/Source/Editor/Content/Proxy/ScriptProxy.cs
index 89a08bb4f..0c8140d1a 100644
--- a/Source/Editor/Content/Proxy/ScriptProxy.cs
+++ b/Source/Editor/Content/Proxy/ScriptProxy.cs
@@ -66,6 +66,15 @@ namespace FlaxEditor.Content
return false;
}
+ ///
+ public override bool IsFileNameValid(string filename)
+ {
+ // Scripts cannot start with digit.
+ if (Char.IsDigit(filename[0]))
+ return false;
+ return true;
+ }
+
///
public override void Create(string outputPath, object arg)
{
diff --git a/Source/Editor/Content/Proxy/SettingsProxy.cs b/Source/Editor/Content/Proxy/SettingsProxy.cs
index a6b74b0ea..2bebc3254 100644
--- a/Source/Editor/Content/Proxy/SettingsProxy.cs
+++ b/Source/Editor/Content/Proxy/SettingsProxy.cs
@@ -3,6 +3,7 @@
using System;
using FlaxEditor.Content.Create;
using FlaxEditor.Content.Settings;
+using FlaxEngine;
namespace FlaxEditor.Content
{
@@ -13,15 +14,18 @@ namespace FlaxEditor.Content
public sealed class SettingsProxy : JsonAssetProxy
{
private readonly Type _type;
+ private readonly SpriteHandle _thumbnail;
///
/// Initializes a new instance of the class.
///
/// The settings asset type (must be subclass of SettingsBase type).
- public SettingsProxy(Type type)
+ /// Asset icon.
+ public SettingsProxy(Type type, SpriteHandle thumbnail)
{
_type = type;
TypeName = type.FullName;
+ _thumbnail = thumbnail;
}
///
@@ -44,6 +48,12 @@ namespace FlaxEditor.Content
Editor.Instance.ContentImporting.Create(new SettingsCreateEntry(outputPath));
}
+ ///
+ public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
+ {
+ return new JsonAssetItem(path, id, typeName, _thumbnail);
+ }
+
///
public override bool IsProxyFor()
{
diff --git a/Source/Editor/Content/Tree/ContentTreeNode.cs b/Source/Editor/Content/Tree/ContentTreeNode.cs
index 78cc7f2b5..9179c3c07 100644
--- a/Source/Editor/Content/Tree/ContentTreeNode.cs
+++ b/Source/Editor/Content/Tree/ContentTreeNode.cs
@@ -77,7 +77,7 @@ namespace FlaxEditor.Content
/// The folder type.
/// The folder path.
protected ContentTreeNode(ContentTreeNode parent, ContentFolderType type, string path)
- : base(false, Editor.Instance.Icons.FolderClosed12, Editor.Instance.Icons.FolderOpened12)
+ : base(false, Editor.Instance.Icons.FolderClosed32, Editor.Instance.Icons.FolderOpen32)
{
_folder = new ContentFolder(type, path, this);
Text = _folder.ShortName;
diff --git a/Source/Editor/Cooker/CookingData.h b/Source/Editor/Cooker/CookingData.h
index c193164f6..77774a9df 100644
--- a/Source/Editor/Cooker/CookingData.h
+++ b/Source/Editor/Cooker/CookingData.h
@@ -7,6 +7,7 @@
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/HashSet.h"
#include "Engine/Core/Collections/Dictionary.h"
+#include "Engine/Core/Types/Guid.h"
class GameCooker;
class PlatformTools;
diff --git a/Source/Editor/Cooker/GameCooker.cpp b/Source/Editor/Cooker/GameCooker.cpp
index c50b10572..f64045ff5 100644
--- a/Source/Editor/Cooker/GameCooker.cpp
+++ b/Source/Editor/Cooker/GameCooker.cpp
@@ -10,6 +10,7 @@
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Content/Content.h"
#include "Engine/Engine/EngineService.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Threading/ThreadSpawner.h"
#include "Engine/Platform/FileSystem.h"
#include "Steps/ValidateStep.h"
diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
index 90d5bfd55..5f097f638 100644
--- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
+++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp
@@ -29,6 +29,7 @@
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Engine/Base/GameBase.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Tools/TextureTool/TextureTool.h"
#if PLATFORM_TOOLS_WINDOWS
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
diff --git a/Source/Editor/Cooker/Steps/DeployDataStep.cpp b/Source/Editor/Cooker/Steps/DeployDataStep.cpp
index ab7f3a7b2..17ddbf73c 100644
--- a/Source/Editor/Cooker/Steps/DeployDataStep.cpp
+++ b/Source/Editor/Cooker/Steps/DeployDataStep.cpp
@@ -7,6 +7,7 @@
#include "Engine/Core/Config/GameSettings.h"
#include "Engine/Renderer/ReflectionsPass.h"
#include "Engine/Renderer/AntiAliasing/SMAA.h"
+#include "Engine/Engine/Globals.h"
bool DeployDataStep::Perform(CookingData& data)
{
diff --git a/Source/Editor/CustomEditors/CustomEditorPresenter.cs b/Source/Editor/CustomEditors/CustomEditorPresenter.cs
index 7f19de195..be7b4de5c 100644
--- a/Source/Editor/CustomEditors/CustomEditorPresenter.cs
+++ b/Source/Editor/CustomEditors/CustomEditorPresenter.cs
@@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors
///
protected override void OnModified()
{
- Presenter.Modified?.Invoke();
+ Presenter.OnModified();
base.OnModified();
}
@@ -354,6 +354,14 @@ namespace FlaxEditor.CustomEditors
ExpandGroups(this, false);
}
+ ///
+ /// Invokes event.
+ ///
+ public void OnModified()
+ {
+ Modified?.Invoke();
+ }
+
///
/// Called when selection gets changed.
///
diff --git a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp
index ffd42d750..519acdf60 100644
--- a/Source/Editor/CustomEditors/CustomEditorsUtil.cpp
+++ b/Source/Editor/CustomEditors/CustomEditorsUtil.cpp
@@ -3,6 +3,7 @@
#include "CustomEditorsUtil.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Types/DateTime.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Engine/EngineService.h"
#include "Engine/Scripting/Scripting.h"
diff --git a/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs b/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs
new file mode 100644
index 000000000..521b844ec
--- /dev/null
+++ b/Source/Editor/CustomEditors/Dedicated/LocalizationSettingsEditor.cs
@@ -0,0 +1,429 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using FlaxEditor.Content.Settings;
+using FlaxEditor.CustomEditors.Editors;
+using FlaxEditor.Scripting;
+using FlaxEngine;
+using FlaxEngine.GUI;
+using FlaxEngine.Utilities;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Object = FlaxEngine.Object;
+
+namespace FlaxEditor.CustomEditors.Dedicated
+{
+ [CustomEditor(typeof(LocalizationSettings))]
+ sealed class LocalizationSettingsEditor : GenericEditor
+ {
+ private CultureInfo _theMostTranslatedCulture;
+ private int _theMostTranslatedCultureCount;
+
+ ///
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ Profiler.BeginEvent("LocalizationSettingsEditor.Initialize");
+ var settings = (LocalizationSettings)Values[0];
+ var tablesLength = settings.LocalizedStringTables?.Length ?? 0;
+ var tables = new List(tablesLength);
+ for (int i = 0; i < tablesLength; i++)
+ {
+ var table = settings.LocalizedStringTables[i];
+ if (table && !table.WaitForLoaded())
+ tables.Add(table);
+ }
+ var locales = tables.GroupBy(x => x.Locale);
+ var tableEntries = new Dictionary>();
+ var allKeys = new HashSet();
+ foreach (var e in locales)
+ {
+ foreach (var table in e)
+ {
+ var entries = table.Entries;
+ tableEntries[table] = entries;
+ allKeys.AddRange(entries.Keys);
+ }
+ }
+
+ {
+ var group = layout.Group("Preview");
+
+ // Current language and culture preview management
+ group.Object("Current Language", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentLanguage, (instance, index) => Localization.CurrentLanguage, (instance, index, value) => Localization.CurrentLanguage = value as CultureInfo), null, "Current UI display language for the game preview.");
+ group.Object("Current Culture", new CustomValueContainer(new ScriptType(typeof(CultureInfo)), Localization.CurrentCulture, (instance, index) => Localization.CurrentCulture, (instance, index, value) => Localization.CurrentCulture = value as CultureInfo), null, "Current values formatting culture for the game preview.");
+ }
+
+ {
+ var group = layout.Group("Locales");
+
+ // Show all existing locales
+ _theMostTranslatedCulture = null;
+ _theMostTranslatedCultureCount = -1;
+ foreach (var e in locales)
+ {
+ var culture = new CultureInfo(e.Key);
+ var prop = group.AddPropertyItem(CultureInfoEditor.GetName(culture), culture.NativeName);
+ int count = e.Sum(x => tableEntries[x].Count);
+ int validCount = e.Sum(x => tableEntries[x].Values.Count(y => y != null && y.Length != 0 && !string.IsNullOrEmpty(y[0])));
+ if (count > _theMostTranslatedCultureCount)
+ {
+ _theMostTranslatedCulture = culture;
+ _theMostTranslatedCultureCount = count;
+ }
+ prop.Label(string.Format("Progress: {0}% ({1}/{2})", (int)(((float)validCount / allKeys.Count * 100.0f)), validCount, allKeys.Count));
+ prop.Label("Tables:");
+ foreach (var table in e)
+ {
+ var namePath = table.Path;
+ if (namePath.StartsWith(Globals.ProjectFolder))
+ namePath = namePath.Substring(Globals.ProjectFolder.Length + 1);
+ var tableLabel = prop.ClickableLabel(namePath).CustomControl;
+ tableLabel.TextColorHighlighted = Color.Wheat;
+ tableLabel.DoubleClick += delegate { Editor.Instance.Windows.ContentWin.Select(table); };
+ }
+ group.Space(10);
+ }
+
+ // Update add button
+ var update = group.Button("Update").Button;
+ update.TooltipText = "Refreshes the dashboard statistics";
+ update.Height = 16.0f;
+ update.Clicked += RebuildLayout;
+
+ // New locale add button
+ var addLocale = group.Button("Add Locale...").Button;
+ addLocale.TooltipText = "Shows a locale picker and creates new localization for it with not translated string tables";
+ addLocale.Height = 16.0f;
+ addLocale.ButtonClicked += delegate(Button button)
+ {
+ var menu = CultureInfoEditor.CreatePicker(null, culture =>
+ {
+ var displayName = CultureInfoEditor.GetName(culture);
+ if (locales.Any(x => x.Key == culture.Name))
+ {
+ MessageBox.Show($"Culture '{displayName}' is already added.");
+ return;
+ }
+ Profiler.BeginEvent("LocalizationSettingsEditor.AddLocale");
+ Editor.Log($"Adding culture '{displayName}' to localization settings");
+ var newTables = settings.LocalizedStringTables.ToList();
+ if (_theMostTranslatedCulture != null)
+ {
+ // Duplicate localization for culture with the highest amount of keys
+ var g = locales.First(x => x.Key == _theMostTranslatedCulture.Name);
+ foreach (var e in g)
+ {
+ var path = e.Path;
+ var filename = Path.GetFileNameWithoutExtension(path);
+ if (filename.EndsWith(_theMostTranslatedCulture.Name))
+ filename = filename.Substring(0, filename.Length - _theMostTranslatedCulture.Name.Length);
+ path = Path.Combine(Path.GetDirectoryName(path), filename + culture.Name + ".json");
+ var table = FlaxEngine.Content.CreateVirtualAsset();
+ table.Locale = culture.Name;
+ var entries = new Dictionary();
+ foreach (var ee in tableEntries[e])
+ {
+ var vv = (string[])ee.Value.Clone();
+ for (var i = 0; i < vv.Length; i++)
+ vv[i] = string.Empty;
+ entries.Add(ee.Key, vv);
+ }
+ table.Entries = entries;
+ if (!table.Save(path))
+ {
+ Object.Destroy(table);
+ newTables.Add(FlaxEngine.Content.LoadAsync(path));
+ }
+ }
+ }
+ else
+ {
+ // No localization so initialize with empty table
+ var path = Path.Combine(Path.Combine(Path.GetDirectoryName(GameSettings.Load().Localization.Path), "Localization", culture.Name + ".json"));
+ var table = FlaxEngine.Content.CreateVirtualAsset();
+ table.Locale = culture.Name;
+ if (!table.Save(path))
+ {
+ Object.Destroy(table);
+ newTables.Add(FlaxEngine.Content.LoadAsync(path));
+ }
+ }
+ settings.LocalizedStringTables = newTables.ToArray();
+ Presenter.OnModified();
+ RebuildLayout();
+ Profiler.EndEvent();
+ });
+ menu.Show(button, new Vector2(0, button.Height));
+ };
+
+ // Export button
+ var exportLocalization = group.Button("Export...").Button;
+ exportLocalization.TooltipText = "Exports the localization strings into .pot file for translation";
+ exportLocalization.Height = 16.0f;
+ exportLocalization.Clicked += delegate
+ {
+ if (FileSystem.ShowSaveFileDialog(null, null, "*.pot", false, "Export localization for translation to .pot file", out var filenames))
+ return;
+ Profiler.BeginEvent("LocalizationSettingsEditor.Export");
+ if (!filenames[0].EndsWith(".pot"))
+ filenames[0] += ".pot";
+ var nplurals = 1;
+ foreach (var e in tableEntries)
+ {
+ foreach (var value in e.Value.Values)
+ {
+ if (value != null && value.Length > nplurals)
+ nplurals = value.Length;
+ }
+ }
+ using (var writer = new StreamWriter(filenames[0], false, Encoding.UTF8))
+ {
+ writer.WriteLine("msgid \"\"");
+ writer.WriteLine("msgstr \"\"");
+ writer.WriteLine("\"Language: English\\n\"");
+ writer.WriteLine("\"MIME-Version: 1.0\\n\"");
+ writer.WriteLine("\"Content-Type: text/plain; charset=UTF-8\\n\"");
+ writer.WriteLine("\"Content-Transfer-Encoding: 8bit\\n\"");
+ writer.WriteLine($"\"Plural-Forms: nplurals={nplurals}; plural=(n != 1);\\n\"");
+ writer.WriteLine("\"X-Generator: FlaxEngine\\n\"");
+ var written = new HashSet();
+ foreach (var e in tableEntries)
+ {
+ foreach (var pair in e.Value)
+ {
+ if (written.Contains(pair.Key))
+ continue;
+ written.Add(pair.Key);
+
+ writer.WriteLine("");
+ writer.WriteLine($"msgid \"{pair.Key}\"");
+ if (pair.Value == null || pair.Value.Length < 2)
+ {
+ writer.WriteLine("msgstr \"\"");
+ }
+ else
+ {
+ writer.WriteLine("msgid_plural \"\"");
+ for (int i = 0; i < pair.Value.Length; i++)
+ writer.WriteLine($"msgstr[{i}] \"\"");
+ }
+ }
+ if (written.Count == allKeys.Count)
+ break;
+ }
+ }
+ Profiler.EndEvent();
+ };
+
+ // Find localized strings in code button
+ var findStringsCode = group.Button("Find localized strings in code").Button;
+ findStringsCode.TooltipText = "Searches for localized string usage in inside a project source files";
+ findStringsCode.Height = 16.0f;
+ findStringsCode.Clicked += delegate
+ {
+ var newKeys = new Dictionary();
+ Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInSource");
+
+ // C#
+ var files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cs", SearchOption.AllDirectories);
+ var filesCount = files.Length;
+ foreach (var file in files)
+ FindNewKeysCSharp(file, newKeys, allKeys);
+
+ // C++
+ files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.cpp", SearchOption.AllDirectories);
+ filesCount += files.Length;
+ foreach (var file in files)
+ FindNewKeysCpp(file, newKeys, allKeys);
+ files = Directory.GetFiles(Globals.ProjectSourceFolder, "*.h", SearchOption.AllDirectories);
+ filesCount += files.Length;
+ foreach (var file in files)
+ FindNewKeysCpp(file, newKeys, allKeys);
+
+ AddNewKeys(newKeys, filesCount, locales, tableEntries);
+ Profiler.EndEvent();
+ };
+
+ // Find localized strings in content button
+ var findStringsContent = group.Button("Find localized strings in content").Button;
+ findStringsContent.TooltipText = "Searches for localized string usage in inside a project content files (scenes, prefabs)";
+ findStringsContent.Height = 16.0f;
+ findStringsContent.Clicked += delegate
+ {
+ var newKeys = new Dictionary();
+ Profiler.BeginEvent("LocalizationSettingsEditor.FindLocalizedStringsInContent");
+
+ // Scenes
+ var files = Directory.GetFiles(Globals.ProjectContentFolder, "*.scene", SearchOption.AllDirectories);
+ var filesCount = files.Length;
+ foreach (var file in files)
+ FindNewKeysJson(file, newKeys, allKeys);
+
+ // Prefabs
+ files = Directory.GetFiles(Globals.ProjectContentFolder, "*.prefab", SearchOption.AllDirectories);
+ filesCount += files.Length;
+ foreach (var file in files)
+ FindNewKeysJson(file, newKeys, allKeys);
+
+ AddNewKeys(newKeys, filesCount, locales, tableEntries);
+ Profiler.EndEvent();
+ };
+ }
+
+ {
+ // Raw asset data editing
+ var group = layout.Group("Data");
+ base.Initialize(group);
+ }
+
+ Profiler.EndEvent();
+ }
+
+ private static void FindNewKeysCSharp(string file, Dictionary newKeys, HashSet allKeys)
+ {
+ var startToken = "Localization.GetString";
+ var textToken = "\"";
+ FindNewKeys(file, newKeys, allKeys, startToken, textToken);
+ }
+
+ private static void FindNewKeysCpp(string file, Dictionary newKeys, HashSet allKeys)
+ {
+ var startToken = "Localization::GetString";
+ var textToken = "TEXT(\"";
+ FindNewKeys(file, newKeys, allKeys, startToken, textToken);
+ }
+
+ private static void FindNewKeys(string file, Dictionary newKeys, HashSet allKeys, string startToken, string textToken)
+ {
+ var contents = File.ReadAllText(file);
+ var idx = contents.IndexOf(startToken);
+ while (idx != -1)
+ {
+ idx += startToken.Length + 1;
+ int braces = 1;
+ int start = idx;
+ while (idx < contents.Length && braces != 0)
+ {
+ if (contents[idx] == '(')
+ braces++;
+ if (contents[idx] == ')')
+ braces--;
+ idx++;
+ }
+ if (idx == contents.Length)
+ break;
+ var inside = contents.Substring(start, idx - start - 1);
+ var textStart = inside.IndexOf(textToken);
+ if (textStart != -1)
+ {
+ textStart += textToken.Length;
+ var textEnd = textStart;
+ while (textEnd < inside.Length && inside[textEnd] != '\"')
+ {
+ if (inside[textEnd] == '\\')
+ textEnd++;
+ textEnd++;
+ }
+ var id = inside.Substring(textStart, textEnd - textStart);
+ textStart = inside.Length > textEnd + 2 ? inside.IndexOf(textToken, textEnd + 2) : -1;
+ string value = null;
+ if (textStart != -1)
+ {
+ textStart += textToken.Length;
+ textEnd = textStart;
+ while (textEnd < inside.Length && inside[textEnd] != '\"')
+ {
+ if (inside[textEnd] == '\\')
+ textEnd++;
+ textEnd++;
+ }
+ value = inside.Substring(textStart, textEnd - textStart);
+ }
+
+ if (!allKeys.Contains(id))
+ newKeys[id] = value;
+ }
+
+ idx = contents.IndexOf(startToken, idx);
+ }
+ }
+
+ private static void FindNewKeysJson(Dictionary newKeys, HashSet allKeys, JToken token)
+ {
+ if (token is JObject o)
+ {
+ foreach (var p in o)
+ {
+ if (string.Equals(p.Key, "Id", StringComparison.Ordinal) && p.Value is JValue i && i.Value is string id && !allKeys.Contains(id))
+ {
+ var count = o.Properties().Count();
+ if (count == 1)
+ {
+ newKeys[id] = null;
+ return;
+ }
+ if (count == 2)
+ {
+ var v = o.Property("Value")?.Value as JValue;
+ if (v?.Value is string value)
+ {
+ newKeys[id] = value;
+ return;
+ }
+ }
+ }
+ FindNewKeysJson(newKeys, allKeys, p.Value);
+ }
+ }
+ else if (token is JArray a)
+ {
+ foreach (var p in a)
+ {
+ FindNewKeysJson(newKeys, allKeys, p);
+ }
+ }
+ }
+
+ private static void FindNewKeysJson(string file, Dictionary newKeys, HashSet allKeys)
+ {
+ using (var reader = new StreamReader(file))
+ using (var jsonReader = new JsonTextReader(reader))
+ {
+ var token = JToken.ReadFrom(jsonReader);
+ FindNewKeysJson(newKeys, allKeys, token);
+ }
+ }
+
+ private void AddNewKeys(Dictionary newKeys, int filesCount, IEnumerable> locales, Dictionary> tableEntries)
+ {
+ Editor.Log($"Found {newKeys.Count} new localized strings in {filesCount} files");
+ if (newKeys.Count == 0)
+ return;
+ foreach (var e in newKeys)
+ Editor.Log(e.Key + (e.Value != null ? " = " + e.Value : string.Empty));
+ foreach (var locale in locales)
+ {
+ var table = locale.First();
+ var entries = tableEntries[table];
+ if (table.Locale == "en")
+ {
+ foreach (var e in newKeys)
+ entries[e.Key] = new[] { e.Value };
+ }
+ else
+ {
+ foreach (var e in newKeys)
+ entries[e.Key] = new[] { string.Empty };
+ }
+ table.Entries = entries;
+ table.Save();
+ }
+ RebuildLayout();
+ }
+ }
+}
diff --git a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs
index 2e5aeade7..141330aea 100644
--- a/Source/Editor/CustomEditors/Editors/CollectionEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/CollectionEditor.cs
@@ -154,9 +154,20 @@ namespace FlaxEditor.CustomEditors.Editors
if (i != 0 && spacing > 0f)
{
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
+ {
+ if (propertiesListElement.Labels.Count > 0)
+ {
+ var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
+ var margin = label.Margin;
+ margin.Bottom += spacing;
+ label.Margin = margin;
+ }
propertiesListElement.Space(spacing);
+ }
else
+ {
layout.Space(spacing);
+ }
}
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
diff --git a/Source/Editor/CustomEditors/Editors/CultureInfoEditor.cs b/Source/Editor/CustomEditors/Editors/CultureInfoEditor.cs
new file mode 100644
index 000000000..67533ed56
--- /dev/null
+++ b/Source/Editor/CustomEditors/Editors/CultureInfoEditor.cs
@@ -0,0 +1,164 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using FlaxEditor.GUI;
+using FlaxEditor.GUI.ContextMenu;
+using FlaxEditor.GUI.Tree;
+using FlaxEditor.Utilities;
+using FlaxEngine;
+using FlaxEngine.GUI;
+
+namespace FlaxEditor.CustomEditors.Editors
+{
+ ///
+ /// Default implementation of the inspector used to edit value type properties. Supports editing property of type (as culture name).
+ ///
+ [CustomEditor(typeof(CultureInfo)), DefaultEditor]
+ internal class CultureInfoEditor : CustomEditor
+ {
+ private ClickableLabel _label;
+
+ ///
+ public override DisplayStyle Style => DisplayStyle.Inline;
+
+ ///
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ _label = layout.ClickableLabel(GetName(Culture)).CustomControl;
+ _label.RightClick += ShowPicker;
+ var button = new Button
+ {
+ Width = 16.0f,
+ Text = "...",
+ Parent = _label,
+ };
+ button.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
+ button.Clicked += ShowPicker;
+ }
+
+ ///
+ public override void Refresh()
+ {
+ base.Refresh();
+
+ _label.Text = GetName(Culture);
+ }
+
+ ///
+ protected override void Deinitialize()
+ {
+ _label = null;
+
+ base.Deinitialize();
+ }
+
+ private CultureInfo Culture
+ {
+ get
+ {
+ if (Values[0] is CultureInfo asCultureInfo)
+ return asCultureInfo;
+ if (Values[0] is string asString)
+ return new CultureInfo(asString);
+ return null;
+ }
+ set
+ {
+ if (Values[0] is CultureInfo)
+ SetValue(value);
+ else if (Values[0] is string)
+ SetValue(value.Name);
+ }
+ }
+
+ private class CultureInfoComparer : IComparer
+ {
+ public int Compare(CultureInfo a, CultureInfo b)
+ {
+ return string.Compare(a.Name, b.Name, StringComparison.Ordinal);
+ }
+ }
+
+ private static void UpdateFilter(TreeNode node, string filterText)
+ {
+ // Update children
+ bool isAnyChildVisible = false;
+ for (int i = 0; i < node.Children.Count; i++)
+ {
+ if (node.Children[i] is TreeNode child)
+ {
+ UpdateFilter(child, filterText);
+ isAnyChildVisible |= child.Visible;
+ }
+ }
+
+ // Update itself
+ bool noFilter = string.IsNullOrWhiteSpace(filterText);
+ bool isThisVisible = noFilter || QueryFilterHelper.Match(filterText, node.Text);
+ bool isExpanded = isAnyChildVisible;
+ if (isExpanded)
+ node.Expand(true);
+ else
+ node.Collapse(true);
+ node.Visible = isThisVisible | isAnyChildVisible;
+ }
+
+ private void ShowPicker()
+ {
+ var menu = CreatePicker(Culture, value => { Culture = value; });
+ menu.Show(_label, new Vector2(0, _label.Height));
+ }
+
+ internal static ContextMenuBase CreatePicker(CultureInfo value, Action changed)
+ {
+ var menu = Utilities.Utils.CreateSearchPopup(out var searchBox, out var tree);
+ tree.Margin = new Margin(-16.0f, 0.0f, -16.0f, -0.0f); // Hide root node
+ var root = tree.AddChild();
+ var cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
+ Array.Sort(cultures, 1, cultures.Length - 2, new CultureInfoComparer()); // at 0 there is Invariant Culture
+ var lcidToNode = new Dictionary();
+ for (var i = 0; i < cultures.Length; i++)
+ {
+ var culture = cultures[i];
+ var node = new TreeNode
+ {
+ Tag = culture,
+ Text = GetName(culture),
+ };
+ if (!lcidToNode.TryGetValue(culture.Parent.LCID, out ContainerControl parent))
+ parent = root;
+ node.Parent = parent;
+ lcidToNode[culture.LCID] = node;
+ }
+ if (value != null)
+ tree.Select((TreeNode)lcidToNode[value.LCID]);
+ tree.SelectedChanged += delegate(List before, List after)
+ {
+ if (after.Count == 1)
+ {
+ menu.Hide();
+ changed((CultureInfo)after[0].Tag);
+ }
+ };
+ searchBox.TextChanged += delegate
+ {
+ if (tree.IsLayoutLocked)
+ return;
+ root.LockChildrenRecursive();
+ var query = searchBox.Text;
+ UpdateFilter(root, query);
+ root.UnlockChildrenRecursive();
+ menu.PerformLayout();
+ };
+ root.ExpandAll(true);
+ return menu;
+ }
+
+ internal static string GetName(CultureInfo value)
+ {
+ return value != null ? string.Format("{0} - {1}", value.Name, value.EnglishName) : null;
+ }
+ }
+}
diff --git a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs
index 4e4048dba..4a94136db 100644
--- a/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/DictionaryEditor.cs
@@ -61,7 +61,7 @@ namespace FlaxEditor.CustomEditors.Editors
var keyType = _editor.Values.Type.GetGenericArguments()[0];
if (keyType == typeof(string) || keyType.IsPrimitive)
{
- var popup = RenamePopup.Show(Parent, Bounds, Text, false);
+ var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
popup.Validate += (renamePopup, value) =>
{
object newKey;
@@ -86,7 +86,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
else if (keyType.IsEnum)
{
- var popup = RenamePopup.Show(Parent, Bounds, Text, false);
+ var popup = RenamePopup.Show(Parent, Rectangle.Margin(Bounds, Margin), Text, false);
var picker = new EnumComboBox(keyType)
{
AnchorPreset = AnchorPresets.StretchAll,
@@ -220,9 +220,20 @@ namespace FlaxEditor.CustomEditors.Editors
if (i != 0 && spacing > 0f)
{
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
+ {
+ if (propertiesListElement.Labels.Count > 0)
+ {
+ var label = propertiesListElement.Labels[propertiesListElement.Labels.Count - 1];
+ var margin = label.Margin;
+ margin.Bottom += spacing;
+ label.Margin = margin;
+ }
propertiesListElement.Space(spacing);
+ }
else
+ {
layout.Space(spacing);
+ }
}
var key = keys.ElementAt(i);
diff --git a/Source/Editor/CustomEditors/Editors/EnumEditor.cs b/Source/Editor/CustomEditors/Editors/EnumEditor.cs
index 7954e18bf..b91c0cf95 100644
--- a/Source/Editor/CustomEditors/Editors/EnumEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/EnumEditor.cs
@@ -9,7 +9,7 @@ using FlaxEngine;
namespace FlaxEditor.CustomEditors.Editors
{
///
- /// Default implementation of the inspector used to edit float value type properties.
+ /// Default implementation of the inspector used to edit enum value type properties.
///
[CustomEditor(typeof(Enum)), DefaultEditor]
public class EnumEditor : CustomEditor
diff --git a/Source/Editor/CustomEditors/Editors/GenericEditor.cs b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
index 264aaeeff..d4079ad79 100644
--- a/Source/Editor/CustomEditors/Editors/GenericEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/GenericEditor.cs
@@ -214,6 +214,7 @@ namespace FlaxEditor.CustomEditors.Editors
public ScriptMemberInfo Target;
public ScriptMemberInfo Source;
public PropertiesListElement PropertiesList;
+ public GroupElement Group;
public bool Invert;
public int LabelIndex;
@@ -257,15 +258,15 @@ namespace FlaxEditor.CustomEditors.Editors
for (int i = 0; i < properties.Length; i++)
{
var p = properties[i];
+ var attributes = p.GetAttributes(true);
+ var showInEditor = attributes.Any(x => x is ShowInEditorAttribute);
// Skip properties without getter or setter
- if (!p.HasGet || !p.HasSet)
+ if (!p.HasGet || (!p.HasSet && !showInEditor))
continue;
-
- var attributes = p.GetAttributes(true);
-
+
// Skip hidden fields, handle special attributes
- if ((!p.IsPublic && !attributes.Any(x => x is ShowInEditorAttribute)) || attributes.Any(x => x is HideInEditorAttribute))
+ if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute))
continue;
items.Add(new ItemInfo(p, attributes));
@@ -379,26 +380,22 @@ namespace FlaxEditor.CustomEditors.Editors
}
}
}
- if (item.VisibleIf != null)
+ if (item.VisibleIf != null && itemLayout.Children.Count > 0)
{
- PropertiesListElement list;
- if (itemLayout.Children.Count > 0 && itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
- {
+ PropertiesListElement list = null;
+ GroupElement group = null;
+ if (itemLayout.Children[itemLayout.Children.Count - 1] is PropertiesListElement list1)
list = list1;
- }
+ else if (itemLayout.Children[itemLayout.Children.Count - 1] is GroupElement group1)
+ group = group1;
else
- {
- // TODO: support inlined objects hiding?
return;
- }
// Get source member used to check rule
var sourceMember = GetVisibleIfSource(item.Info.DeclaringType, item.VisibleIf);
if (sourceMember == ScriptType.Null)
return;
- // Find the target control to show/hide
-
// Resize cache
if (_visibleIfCaches == null)
_visibleIfCaches = new VisibleIfCache[8];
@@ -414,6 +411,7 @@ namespace FlaxEditor.CustomEditors.Editors
Target = item.Info,
Source = sourceMember,
PropertiesList = list,
+ Group = group,
LabelIndex = labelIndex,
Invert = item.VisibleIf.Invert,
};
@@ -569,8 +567,7 @@ namespace FlaxEditor.CustomEditors.Editors
{
for (int i = 0; i < _visibleIfCaches.Length; i++)
{
- var c = _visibleIfCaches[i];
-
+ ref var c = ref _visibleIfCaches[i];
if (c.Target == ScriptMemberInfo.Null)
break;
@@ -586,7 +583,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
// Apply the visibility (note: there may be no label)
- if (c.LabelIndex != -1 && c.PropertiesList.Labels.Count > c.LabelIndex)
+ if (c.LabelIndex != -1 && c.PropertiesList != null && c.PropertiesList.Labels.Count > c.LabelIndex)
{
var label = c.PropertiesList.Labels[c.LabelIndex];
label.Visible = visible;
@@ -599,6 +596,10 @@ namespace FlaxEditor.CustomEditors.Editors
child.Visible = visible;
}
}
+ if (c.Group != null)
+ {
+ c.Group.Panel.Visible = visible;
+ }
}
}
catch (Exception ex)
diff --git a/Source/Editor/CustomEditors/Editors/LocalizedStringEditor.cs b/Source/Editor/CustomEditors/Editors/LocalizedStringEditor.cs
new file mode 100644
index 000000000..82503d9bc
--- /dev/null
+++ b/Source/Editor/CustomEditors/Editors/LocalizedStringEditor.cs
@@ -0,0 +1,234 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using FlaxEditor.Content.Settings;
+using FlaxEditor.CustomEditors.Elements;
+using FlaxEditor.GUI.Tree;
+using FlaxEditor.Scripting;
+using FlaxEditor.Utilities;
+using FlaxEngine;
+using FlaxEngine.GUI;
+using Utils = FlaxEditor.Utilities.Utils;
+
+namespace FlaxEditor.CustomEditors.Editors
+{
+ ///
+ /// Default implementation of the inspector used to edit localized string properties.
+ ///
+ [CustomEditor(typeof(LocalizedString)), DefaultEditor]
+ public sealed class LocalizedStringEditor : GenericEditor
+ {
+ private TextBoxElement _idElement, _valueElement;
+
+ ///
+ public override DisplayStyle Style => DisplayStyle.Inline;
+
+ ///
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ base.Initialize(layout);
+
+ if (layout.Children.Count == 0)
+ return;
+ var propList = layout.Children[layout.Children.Count - 1] as PropertiesListElement;
+ if (propList == null || propList.Children.Count != 2)
+ return;
+ var idElement = propList.Children[0] as TextBoxElement;
+ var valueElement = propList.Children[1] as TextBoxElement;
+ if (idElement == null || valueElement == null)
+ return;
+ _idElement = idElement;
+ _valueElement = valueElement;
+
+ var attributes = Values.GetAttributes();
+ var multiLine = attributes?.FirstOrDefault(x => x is MultilineTextAttribute);
+ if (multiLine != null)
+ {
+ valueElement.TextBox.IsMultiline = true;
+ valueElement.TextBox.Height *= 3;
+ }
+
+ var selectString = new Button
+ {
+ Width = 16.0f,
+ Text = "...",
+ TooltipText = "Select localized text from Localization Settings...",
+ Parent = idElement.TextBox,
+ };
+ selectString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
+ selectString.ButtonClicked += OnSelectStringClicked;
+
+ var addString = new Button
+ {
+ Width = 16.0f,
+ Text = "+",
+ TooltipText = "Add new localized text to Localization Settings (all used locales)",
+ Parent = _valueElement.TextBox,
+ Enabled = IsSingleObject,
+ };
+ addString.SetAnchorPreset(AnchorPresets.MiddleRight, false, true);
+ addString.ButtonClicked += OnAddStringClicked;
+ }
+
+ ///
+ internal override void RefreshInternal()
+ {
+ base.RefreshInternal();
+
+ if (_valueElement != null)
+ {
+ _valueElement.TextBox.WatermarkText = Localization.GetString(_idElement.Text);
+ }
+ }
+
+ ///
+ protected override void Deinitialize()
+ {
+ base.Deinitialize();
+
+ _idElement = null;
+ _valueElement = null;
+ }
+
+ private void OnSelectStringClicked(Button button)
+ {
+ var settings = GameSettings.Load();
+ if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
+ {
+ MessageBox.Show("No valid localization settings setup.");
+ return;
+ }
+ Profiler.BeginEvent("LocalizedStringEditor.OnSelectStringClicked");
+ var allKeys = new HashSet();
+ for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
+ {
+ var table = settings.LocalizedStringTables[i];
+ if (table && !table.WaitForLoaded())
+ {
+ var entries = table.Entries;
+ foreach (var e in entries)
+ allKeys.Add(e.Key);
+ }
+ }
+ var allKeysSorted = allKeys.ToList();
+ allKeysSorted.Sort();
+ var value = _idElement?.TextBox.Text;
+ var menu = Utils.CreateSearchPopup(out var searchBox, out var tree);
+ var idToNode = new TreeNode[allKeysSorted.Count];
+ for (var i = 0; i < allKeysSorted.Count; i++)
+ {
+ var key = allKeysSorted[i];
+ var node = new TreeNode
+ {
+ Text = key,
+ TooltipText = Localization.GetString(key),
+ Parent = tree,
+ };
+ if (key == value)
+ tree.Select(node);
+ idToNode[i] = node;
+ }
+ tree.SelectedChanged += delegate(List before, List after)
+ {
+ if (after.Count == 1)
+ {
+ menu.Hide();
+ _idElement.TextBox.SetTextAsUser(after[0].Text);
+ }
+ };
+ searchBox.TextChanged += delegate
+ {
+ if (tree.IsLayoutLocked)
+ return;
+ tree.LockChildrenRecursive();
+ var query = searchBox.Text;
+ for (int i = 0; i < idToNode.Length; i++)
+ {
+ var node = idToNode[i];
+ node.Visible = string.IsNullOrWhiteSpace(query) || QueryFilterHelper.Match(query, node.Text);
+ }
+ tree.UnlockChildrenRecursive();
+ menu.PerformLayout();
+ };
+ menu.Show(button, new Vector2(0, button.Height));
+ Profiler.EndEvent();
+ }
+
+ private void OnAddStringClicked(Button button)
+ {
+ var settings = GameSettings.Load();
+ if (settings?.LocalizedStringTables == null || settings.LocalizedStringTables.Length == 0)
+ {
+ MessageBox.Show("No valid localization settings setup.");
+ return;
+ }
+ Profiler.BeginEvent("LocalizedStringEditor.OnAddStringClicked");
+ var allKeys = new HashSet();
+ for (int i = 0; i < settings.LocalizedStringTables.Length; i++)
+ {
+ var table = settings.LocalizedStringTables[i];
+ if (table && !table.WaitForLoaded())
+ {
+ var entries = table.Entries;
+ foreach (var e in entries)
+ allKeys.Add(e.Key);
+ }
+ }
+ _valueElement.TextBox.SetTextAsUser(null);
+ string newKey = null;
+ if (string.IsNullOrEmpty(_idElement.Text))
+ {
+ CustomEditor customEditor = this;
+ while (customEditor?.Values != null)
+ {
+ if (customEditor.Values.Info != ScriptMemberInfo.Null)
+ if (newKey == null)
+ newKey = customEditor.Values.Info.Name;
+ else
+ newKey = customEditor.Values.Info.Name + '.' + newKey;
+ else if (customEditor.Values[0] is SceneObject sceneObject)
+ if (newKey == null)
+ newKey = sceneObject.GetNamePath('.');
+ else
+ newKey = sceneObject.GetNamePath('.') + '.' + newKey;
+ else
+ break;
+ customEditor = customEditor.ParentEditor;
+ }
+ if (string.IsNullOrWhiteSpace(newKey))
+ newKey = Guid.NewGuid().ToString("N");
+ }
+ else
+ {
+ newKey = _idElement.Text;
+ }
+ if (allKeys.Contains(newKey))
+ {
+ Profiler.EndEvent();
+ if (_idElement.Text != newKey)
+ _idElement.TextBox.SetTextAsUser(newKey);
+ else
+ MessageBox.Show("Already added.");
+ return;
+ }
+ var newValue = _valueElement.Text;
+ Editor.Log(newKey + (newValue != null ? " = " + newValue : string.Empty));
+ var locales = settings.LocalizedStringTables.GroupBy(x => x.Locale);
+ foreach (var locale in locales)
+ {
+ var table = locale.First();
+ var entries = table.Entries;
+ if (table.Locale == "en")
+ entries[newKey] = new[] { newValue };
+ else
+ entries[newKey] = new[] { string.Empty };
+ table.Entries = entries;
+ table.Save();
+ }
+ _idElement.TextBox.SetTextAsUser(newKey);
+ Profiler.EndEvent();
+ }
+ }
+}
diff --git a/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs b/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs
index 7724acf18..dcdf3114b 100644
--- a/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs
+++ b/Source/Editor/CustomEditors/Editors/ObjectSwitcherEditor.cs
@@ -3,7 +3,6 @@
using System;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
-using FlaxEngine;
namespace FlaxEditor.CustomEditors.Editors
{
diff --git a/Source/Editor/CustomEditors/Elements/Container/HorizontalPanelElement.cs b/Source/Editor/CustomEditors/Elements/Container/HorizontalPanelElement.cs
index 2958cd337..de015a371 100644
--- a/Source/Editor/CustomEditors/Elements/Container/HorizontalPanelElement.cs
+++ b/Source/Editor/CustomEditors/Elements/Container/HorizontalPanelElement.cs
@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Elements
{
///
- /// The vertical panel element.
+ /// The horizontal panel element.
///
///
- public class VerticalPanelElement : LayoutElementsContainer
+ public class HorizontalPanelElement : LayoutElementsContainer
{
///
/// The panel.
///
- public readonly VerticalPanel Panel = new VerticalPanel();
+ public readonly HorizontalPanel Panel = new HorizontalPanel();
///
public override ContainerControl ContainerControl => Panel;
diff --git a/Source/Editor/CustomEditors/Elements/Container/VerticalPanelElement.cs b/Source/Editor/CustomEditors/Elements/Container/VerticalPanelElement.cs
index de015a371..2958cd337 100644
--- a/Source/Editor/CustomEditors/Elements/Container/VerticalPanelElement.cs
+++ b/Source/Editor/CustomEditors/Elements/Container/VerticalPanelElement.cs
@@ -5,15 +5,15 @@ using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Elements
{
///
- /// The horizontal panel element.
+ /// The vertical panel element.
///
///
- public class HorizontalPanelElement : LayoutElementsContainer
+ public class VerticalPanelElement : LayoutElementsContainer
{
///
/// The panel.
///
- public readonly HorizontalPanel Panel = new HorizontalPanel();
+ public readonly VerticalPanel Panel = new VerticalPanel();
///
public override ContainerControl ContainerControl => Panel;
diff --git a/Source/Editor/CustomEditors/LayoutElementsContainer.cs b/Source/Editor/CustomEditors/LayoutElementsContainer.cs
index ae33599c1..6f645789a 100644
--- a/Source/Editor/CustomEditors/LayoutElementsContainer.cs
+++ b/Source/Editor/CustomEditors/LayoutElementsContainer.cs
@@ -112,7 +112,7 @@ namespace FlaxEditor.CustomEditors
OnAddElement(element);
return element;
}
-
+
///
/// Adds new horizontal panel element.
///
@@ -690,6 +690,17 @@ namespace FlaxEditor.CustomEditors
return element;
}
+ ///
+ /// Adds custom element to the layout.
+ ///
+ /// The element.
+ public void AddElement(LayoutElement element)
+ {
+ if (element == null)
+ throw new ArgumentNullException();
+ OnAddElement(element);
+ }
+
///
/// Called when element is added to the layout.
///
diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs
index 8f90d203f..adf4d566b 100644
--- a/Source/Editor/Editor.cs
+++ b/Source/Editor/Editor.cs
@@ -220,7 +220,7 @@ namespace FlaxEditor
GameProject = ProjectInfo.Load(Internal_GetProjectPath());
Icons = new EditorIcons();
- Icons.GetIcons();
+ Icons.LoadIcons();
// Create common editor modules
RegisterModule(Options = new OptionsModule(this));
@@ -878,10 +878,12 @@ namespace FlaxEditor
/// Checks if can import asset with the given extension.
///
/// The file extension.
+ /// The output file extension (flax, json, etc.).
/// True if can import files with given extension, otherwise false.
- public static bool CanImport(string extension)
+ public static bool CanImport(string extension, out string outputExtension)
{
- return Internal_CanImport(extension);
+ outputExtension = Internal_CanImport(extension);
+ return outputExtension != null;
}
///
@@ -1183,6 +1185,8 @@ namespace FlaxEditor
var win = Windows.GameWin.Root;
if (win?.RootWindow is WindowRootControl root && root.Window && root.Window.IsFocused)
{
+ if (StateMachine.IsPlayMode && StateMachine.PlayingState.IsPaused)
+ return false;
return true;
}
}
@@ -1369,7 +1373,7 @@ namespace FlaxEditor
internal static extern bool Internal_CreateVisualScript(string outputPath, string baseTypename);
[MethodImpl(MethodImplOptions.InternalCall)]
- internal static extern bool Internal_CanImport(string extension);
+ internal static extern string Internal_CanImport(string extension);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool Internal_CanExport(string path);
diff --git a/Source/Editor/EditorIcons.cs b/Source/Editor/EditorIcons.cs
index 700b5e25e..d4b89b8d3 100644
--- a/Source/Editor/EditorIcons.cs
+++ b/Source/Editor/EditorIcons.cs
@@ -16,102 +16,124 @@ namespace FlaxEditor
[HideInEditor]
public sealed class EditorIcons
{
- public SpriteHandle FolderClosed12;
- public SpriteHandle FolderOpened12;
+ // 12px
public SpriteHandle DragBar12;
- public SpriteHandle ArrowDown12;
- public SpriteHandle ArrowRight12;
public SpriteHandle Search12;
+ public SpriteHandle WindowDrag12;
+ public SpriteHandle CheckBoxIntermediate12;
+ public SpriteHandle ArrowRight12;
public SpriteHandle Settings12;
public SpriteHandle Cross12;
- public SpriteHandle CheckBoxIntermediate12;
public SpriteHandle CheckBoxTick12;
- public SpriteHandle StatusBarSizeGrip12;
+ public SpriteHandle ArrowDown12;
- public SpriteHandle ArrowRightBorder16;
- public SpriteHandle World16;
- public SpriteHandle ScaleStep16;
- public SpriteHandle RotateStep16;
- public SpriteHandle Grid16;
- public SpriteHandle Translate16;
- public SpriteHandle Rotate16;
- public SpriteHandle Scale16;
- public SpriteHandle Link16;
- public SpriteHandle Docs16;
-
- public SpriteHandle Save32;
- public SpriteHandle Undo32;
- public SpriteHandle Redo32;
+ // 32px
+ public SpriteHandle Scalar32;
public SpriteHandle Translate32;
public SpriteHandle Rotate32;
public SpriteHandle Scale32;
- public SpriteHandle Play32;
- public SpriteHandle Pause32;
- public SpriteHandle Step32;
- public SpriteHandle Stop32;
- public SpriteHandle PageScale32;
- public SpriteHandle Bone32;
- public SpriteHandle Docs32;
- public SpriteHandle Import32;
- public SpriteHandle AddDoc32;
- public SpriteHandle RemoveDoc32;
- public SpriteHandle BracketsSlash32;
- public SpriteHandle Find32;
- public SpriteHandle Reload32;
- public SpriteHandle ArrowLeft32;
- public SpriteHandle ArrowRight32;
- public SpriteHandle ArrowDown32;
- public SpriteHandle ArrowUp32;
- public SpriteHandle Error32;
- public SpriteHandle Warning32;
- public SpriteHandle Info32;
- public SpriteHandle UV32;
- public SpriteHandle Image32;
+ public SpriteHandle Grid32;
+ public SpriteHandle Flax32;
+ public SpriteHandle RotateSnap32;
+ public SpriteHandle ScaleSnap32;
+ public SpriteHandle Globe32;
+ public SpriteHandle CamSpeed32;
public SpriteHandle Link32;
- public SpriteHandle Next32;
- public SpriteHandle Camera32;
- public SpriteHandle Build32;
+ public SpriteHandle Add32;
+ public SpriteHandle Left32;
+ public SpriteHandle Right32;
+ public SpriteHandle Up32;
+ public SpriteHandle Down32;
+ public SpriteHandle FolderClosed32;
+ public SpriteHandle FolderOpen32;
- public SpriteHandle Add48;
- public SpriteHandle Paint48;
- public SpriteHandle Foliage48;
- public SpriteHandle Mountain48;
+ // Visject
+ public SpriteHandle VisjectBoxOpen32;
+ public SpriteHandle VisjectBoxClosed32;
+ public SpriteHandle VisjectArrowOpen32;
+ public SpriteHandle VisjectArrowClosed32;
- public SpriteHandle Plugin64;
- public SpriteHandle Document64;
- public SpriteHandle CSharpScript64;
- public SpriteHandle CppScript64;
+ // 64px
+ public SpriteHandle Flax64;
+ public SpriteHandle Save64;
+ public SpriteHandle Play64;
+ public SpriteHandle Stop64;
+ public SpriteHandle Pause64;
+ public SpriteHandle Skip64;
+ public SpriteHandle Info64;
+ public SpriteHandle Error64;
+ public SpriteHandle Warning64;
+ public SpriteHandle AddFile64;
+ public SpriteHandle DeleteFile64;
+ public SpriteHandle Import64;
+ public SpriteHandle Left64;
+ public SpriteHandle Right64;
+ public SpriteHandle Up64;
+ public SpriteHandle Down64;
+ public SpriteHandle Undo64;
+ public SpriteHandle Redo64;
+ public SpriteHandle Translate64;
+ public SpriteHandle Rotate64;
+ public SpriteHandle Scale64;
+ public SpriteHandle Refresh64;
+ public SpriteHandle Shift64;
+ public SpriteHandle Code64;
public SpriteHandle Folder64;
- public SpriteHandle Scene64;
- public SpriteHandle CodeScript64;
+ public SpriteHandle CenterView64;
+ public SpriteHandle Image64;
+ public SpriteHandle Camera64;
+ public SpriteHandle Docs64;
+ public SpriteHandle Search64;
+ public SpriteHandle Bone64;
+ public SpriteHandle Link64;
+ public SpriteHandle Build64;
+ public SpriteHandle Add64;
- public SpriteHandle Logo128;
+ // 96px
+ public SpriteHandle Toolbox96;
+ public SpriteHandle Paint96;
+ public SpriteHandle Foliage96;
+ public SpriteHandle Terrain96;
- public SpriteHandle VisjectBoxOpen;
- public SpriteHandle VisjectBoxClose;
- public SpriteHandle VisjectArrowOpen;
- public SpriteHandle VisjectArrowClose;
+ // 128px
+ public SpriteHandle AndroidSettings128;
+ public SpriteHandle PlaystationSettings128;
+ public SpriteHandle InputSettings128;
+ public SpriteHandle PhysicsSettings128;
+ public SpriteHandle CSharpScript128;
+ public SpriteHandle Folder128;
+ public SpriteHandle WindowsIcon128;
+ public SpriteHandle LinuxIcon128;
+ public SpriteHandle UWPSettings128;
+ public SpriteHandle XBOXSettings128;
+ public SpriteHandle LayersTagsSettings128;
+ public SpriteHandle GraphicsSettings128;
+ public SpriteHandle CPPScript128;
+ public SpriteHandle Plugin128;
+ public SpriteHandle XBoxScarletIcon128;
+ public SpriteHandle AssetShadow128;
+ public SpriteHandle WindowsSettings128;
+ public SpriteHandle TimeSettings128;
+ public SpriteHandle GameSettings128;
+ public SpriteHandle VisualScript128;
+ public SpriteHandle Document128;
+ public SpriteHandle XBoxOne128;
+ public SpriteHandle UWPStore128;
+ public SpriteHandle ColorWheel128;
+ public SpriteHandle LinuxSettings128;
+ public SpriteHandle NavigationSettings128;
+ public SpriteHandle AudioSettings128;
+ public SpriteHandle BuildSettings128;
+ public SpriteHandle Scene128;
+ public SpriteHandle AndroidIcon128;
+ public SpriteHandle PS4Icon128;
+ public SpriteHandle FlaxLogo128;
- public SpriteHandle AssetShadow;
- public SpriteHandle ColorWheel;
- public SpriteHandle Windows;
- public SpriteHandle XboxOne;
- public SpriteHandle WindowsStore;
- public SpriteHandle Linux;
- public SpriteHandle PS4;
- public SpriteHandle XboxSeriesX;
- public SpriteHandle Android;
-
- internal void GetIcons()
+ internal void LoadIcons()
{
- // Load asset
+ // Load & validate
var iconsAtlas = FlaxEngine.Content.LoadAsyncInternal(EditorAssets.IconsAtlas);
- if (iconsAtlas == null)
- {
- Editor.LogError("Cannot load editor icons atlas.");
- return;
- }
- if (iconsAtlas.WaitForLoaded())
+ if (iconsAtlas is null || iconsAtlas.WaitForLoaded())
{
Editor.LogError("Failed to load editor icons atlas.");
return;
@@ -122,11 +144,11 @@ namespace FlaxEditor
for (int i = 0; i < fields.Length; i++)
{
var field = fields[i];
+
var sprite = iconsAtlas.FindSprite(field.Name);
if (!sprite.IsValid)
- {
- Editor.LogWarning(string.Format("Failed to load sprite icon \'{0}\'.", field.Name));
- }
+ Editor.LogWarning($"Failed to load sprite icon \'{field.Name}\'.");
+
field.SetValue(this, sprite);
}
}
diff --git a/Source/Editor/GUI/ComboBox.cs b/Source/Editor/GUI/ComboBox.cs
index aa1c13c8a..d06c1eef9 100644
--- a/Source/Editor/GUI/ComboBox.cs
+++ b/Source/Editor/GUI/ComboBox.cs
@@ -349,6 +349,8 @@ namespace FlaxEditor.GUI
///
protected virtual void OnSelectedIndexChanged()
{
+ if (_tooltips != null && _tooltips.Length == _items.Count)
+ TooltipText = _selectedIndices.Count == 1 ? _tooltips[_selectedIndices[0]] : null;
SelectedIndexChanged?.Invoke(this);
}
diff --git a/Source/Editor/GUI/ContextMenu/ContextMenu.cs b/Source/Editor/GUI/ContextMenu/ContextMenu.cs
index 04dded53c..966f3502b 100644
--- a/Source/Editor/GUI/ContextMenu/ContextMenu.cs
+++ b/Source/Editor/GUI/ContextMenu/ContextMenu.cs
@@ -439,7 +439,7 @@ namespace FlaxEditor.GUI.ContextMenu
}
}
}
- if (startIndex != -1)
+ if (startIndex > 0 && startIndex <= _panel.Children.Count)
{
// No more items found so start from the top if there are matching items
_panel.Children[startIndex - 1].Defocus();
diff --git a/Source/Editor/GUI/Dialogs/ColorSelector.cs b/Source/Editor/GUI/Dialogs/ColorSelector.cs
index da1b913a5..0cfc452fe 100644
--- a/Source/Editor/GUI/Dialogs/ColorSelector.cs
+++ b/Source/Editor/GUI/Dialogs/ColorSelector.cs
@@ -61,7 +61,7 @@ namespace FlaxEditor.GUI.Dialogs
public ColorSelector(float wheelSize = 64)
: base(0, 0, wheelSize, wheelSize)
{
- _colorWheelSprite = Editor.Instance.Icons.ColorWheel;
+ _colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
}
diff --git a/Source/Editor/GUI/Docking/DockPanelProxy.cs b/Source/Editor/GUI/Docking/DockPanelProxy.cs
index 1f6b3924e..fbc9d7bee 100644
--- a/Source/Editor/GUI/Docking/DockPanelProxy.cs
+++ b/Source/Editor/GUI/Docking/DockPanelProxy.cs
@@ -348,7 +348,7 @@ namespace FlaxEditor.GUI.Docking
// Cache data
IsMouseRightButtonDown = true;
if (MouseDownWindow != null)
- _panel.SelectTab(MouseDownWindow);
+ _panel.SelectTab(MouseDownWindow, false);
}
else if (button == MouseButton.Middle)
{
diff --git a/Source/Editor/GUI/EnumComboBox.cs b/Source/Editor/GUI/EnumComboBox.cs
index 34a2dae35..ed1c80cd6 100644
--- a/Source/Editor/GUI/EnumComboBox.cs
+++ b/Source/Editor/GUI/EnumComboBox.cs
@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI
///
/// The cached value from the UI.
///
- protected ulong _cachedValue;
+ protected long _cachedValue;
///
/// True if has value cached, otherwise false.
@@ -54,7 +54,7 @@ namespace FlaxEditor.GUI
///
/// The value.
///
- public ulong Value;
+ public long Value;
///
/// Initializes a new instance of the struct.
@@ -62,7 +62,7 @@ namespace FlaxEditor.GUI
/// The name.
/// The tooltip.
/// The value.
- public Entry(string name, ulong value, string tooltip = null)
+ public Entry(string name, long value, string tooltip = null)
{
Name = name;
Tooltip = tooltip;
@@ -88,13 +88,13 @@ namespace FlaxEditor.GUI
public object EnumTypeValue
{
get => Enum.ToObject(_enumType, Value);
- set => Value = Convert.ToUInt64(value);
+ set => Value = Convert.ToInt64(value);
}
///
/// Gets or sets the value.
///
- public ulong Value
+ public long Value
{
get => _cachedValue;
set
@@ -209,7 +209,7 @@ namespace FlaxEditor.GUI
///
protected void CacheValue()
{
- ulong value = 0;
+ long value = 0;
if (IsFlags)
{
var selection = Selection;
@@ -276,7 +276,7 @@ namespace FlaxEditor.GUI
tooltip = tooltipAttr.Text;
}
- entries.Add(new Entry(name, Convert.ToUInt64(field.GetRawConstantValue()), tooltip));
+ entries.Add(new Entry(name, Convert.ToInt64(field.GetRawConstantValue()), tooltip));
}
}
@@ -295,9 +295,9 @@ namespace FlaxEditor.GUI
}
// Calculate value that will be set after change
- ulong valueAfter = 0;
+ long valueAfter = 0;
bool isSelected = _selectedIndices.Contains(index);
- ulong selectedValue = entries[index].Value;
+ long selectedValue = entries[index].Value;
for (int i = 0; i < _selectedIndices.Count; i++)
{
int selectedIndex = _selectedIndices[i];
diff --git a/Source/Editor/GUI/Input/FloatValueBox.cs b/Source/Editor/GUI/Input/FloatValueBox.cs
index 1bbd56c9a..e66fb721b 100644
--- a/Source/Editor/GUI/Input/FloatValueBox.cs
+++ b/Source/Editor/GUI/Input/FloatValueBox.cs
@@ -23,10 +23,7 @@ namespace FlaxEditor.GUI.Input
value = Mathf.Clamp(value, _min, _max);
if (Math.Abs(_value - value) > Mathf.Epsilon)
{
- // Set value
_value = value;
-
- // Update
UpdateText();
OnValueChanged();
}
@@ -43,7 +40,6 @@ namespace FlaxEditor.GUI.Input
{
if (value > _max)
throw new ArgumentException();
-
_min = value;
Value = Value;
}
@@ -60,7 +56,6 @@ namespace FlaxEditor.GUI.Input
{
if (value < _min)
throw new ArgumentException();
-
_max = value;
Value = Value;
}
@@ -80,9 +75,19 @@ namespace FlaxEditor.GUI.Input
public FloatValueBox(float value, float x = 0, float y = 0, float width = 120, float min = float.MinValue, float max = float.MaxValue, float slideSpeed = 1)
: base(Mathf.Clamp(value, min, max), x, y, width, min, max, slideSpeed)
{
+ TryUseAutoSliderSpeed();
UpdateText();
}
+ private void TryUseAutoSliderSpeed()
+ {
+ var range = _max - _min;
+ if (Mathf.IsOne(_slideSpeed) && range > Mathf.Epsilon * 200.0f && range < 1000000.0f)
+ {
+ _slideSpeed = range * 0.01f;
+ }
+ }
+
///
/// Sets the value limits.
///
@@ -103,6 +108,7 @@ namespace FlaxEditor.GUI.Input
{
_min = limits.Min;
_max = Mathf.Max(_min, limits.Max);
+ TryUseAutoSliderSpeed();
Value = Value;
}
@@ -115,6 +121,7 @@ namespace FlaxEditor.GUI.Input
_min = limits.Min;
_max = Mathf.Max(_min, limits.Max);
_slideSpeed = limits.SliderSpeed;
+ TryUseAutoSliderSpeed();
Value = Value;
}
diff --git a/Source/Editor/GUI/Input/ValueBox.cs b/Source/Editor/GUI/Input/ValueBox.cs
index d34acd17b..b1b0408bd 100644
--- a/Source/Editor/GUI/Input/ValueBox.cs
+++ b/Source/Editor/GUI/Input/ValueBox.cs
@@ -184,7 +184,7 @@ namespace FlaxEditor.GUI.Input
var style = Style.Current;
// Draw sliding UI
- Render2D.DrawSprite(style.Scale, SlideRect, style.Foreground);
+ Render2D.DrawSprite(style.Scalar, SlideRect, style.Foreground);
// Check if is sliding
if (_isSliding)
diff --git a/Source/Editor/GUI/PlatformSelector.cs b/Source/Editor/GUI/PlatformSelector.cs
index ea0773a69..cc7bc003a 100644
--- a/Source/Editor/GUI/PlatformSelector.cs
+++ b/Source/Editor/GUI/PlatformSelector.cs
@@ -82,14 +82,15 @@ namespace FlaxEditor.GUI
var icons = Editor.Instance.Icons;
var platforms = new[]
{
- new PlatformData(PlatformType.Windows, icons.Windows, "Windows"),
- new PlatformData(PlatformType.XboxOne, icons.XboxOne, "Xbox One"),
- new PlatformData(PlatformType.UWP, icons.WindowsStore, "Windows Store"),
- new PlatformData(PlatformType.Linux, icons.Linux, "Linux"),
- new PlatformData(PlatformType.PS4, icons.PS4, "PlayStation 4"),
- new PlatformData(PlatformType.XboxScarlett, icons.XboxSeriesX, "Xbox Scarlett"),
- new PlatformData(PlatformType.Android, icons.Android, "Android"),
- new PlatformData(PlatformType.Switch, icons.ColorWheel, "Switch"),
+ new PlatformData(PlatformType.Windows, icons.WindowsIcon128, "Windows"),
+ new PlatformData(PlatformType.XboxOne, icons.XBoxOne128, "Xbox One"),
+ new PlatformData(PlatformType.UWP, icons.UWPStore128, "Windows Store"),
+ new PlatformData(PlatformType.Linux, icons.LinuxIcon128, "Linux"),
+ new PlatformData(PlatformType.PS4, icons.PS4Icon128, "PlayStation 4"),
+ new PlatformData(PlatformType.XboxScarlett, icons.XBoxScarletIcon128, "Xbox Scarlett"),
+ new PlatformData(PlatformType.Android, icons.AndroidIcon128, "Android"),
+ new PlatformData(PlatformType.Switch, icons.ColorWheel128, "Switch"),
+
};
const float IconSize = 48.0f;
diff --git a/Source/Editor/GUI/Popups/TypeSearchPopup.cs b/Source/Editor/GUI/Popups/TypeSearchPopup.cs
index f1300d299..a35b2a1c5 100644
--- a/Source/Editor/GUI/Popups/TypeSearchPopup.cs
+++ b/Source/Editor/GUI/Popups/TypeSearchPopup.cs
@@ -79,7 +79,7 @@ namespace FlaxEditor.GUI
var type = allTypes[i];
if (_isValid(type))
{
- var attributes = type.GetAttributes(false);
+ var attributes = type.GetAttributes(true);
if (attributes.FirstOrDefault(x => x is HideInEditorAttribute) == null)
{
AddItem(new TypeItemView(type, attributes));
diff --git a/Source/Editor/GUI/Timeline/GUI/GradientEditor.cs b/Source/Editor/GUI/Timeline/GUI/GradientEditor.cs
index 1fc3578cb..916568571 100644
--- a/Source/Editor/GUI/Timeline/GUI/GradientEditor.cs
+++ b/Source/Editor/GUI/Timeline/GUI/GradientEditor.cs
@@ -63,7 +63,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
var isMouseOver = IsMouseOver;
var color = Gradient._data[Index].Value;
var icons = Editor.Instance.Icons;
- var icon = icons.VisjectBoxClose;
+ var icon = icons.VisjectBoxClosed32;
Render2D.DrawSprite(icon, new Rectangle(0.0f, 0.0f, 10.0f, 10.0f), isMouseOver ? Color.Gray : Color.Black);
Render2D.DrawSprite(icon, new Rectangle(1.0f, 1.0f, 8.0f, 8.0f), color);
diff --git a/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs b/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
index 079ef9957..93d9261e5 100644
--- a/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
+++ b/Source/Editor/GUI/Timeline/GUI/PositionHandle.cs
@@ -26,7 +26,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
public override void Draw()
{
var style = Style.Current;
- var icon = Editor.Instance.Icons.VisjectArrowClose;
+ var icon = Editor.Instance.Icons.VisjectArrowClosed32;
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y;
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
diff --git a/Source/Editor/GUI/Timeline/Timeline.cs b/Source/Editor/GUI/Timeline/Timeline.cs
index 56f8620c6..58e6a0f32 100644
--- a/Source/Editor/GUI/Timeline/Timeline.cs
+++ b/Source/Editor/GUI/Timeline/Timeline.cs
@@ -738,7 +738,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[0] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline start (Home)",
- Brush = new SpriteBrush(icons.Step32),
+ Brush = new SpriteBrush(icons.Skip64),
Enabled = false,
Visible = false,
Rotation = 180.0f,
@@ -750,7 +750,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[1] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Seek back to the previous keyframe (Page Down)",
- Brush = new SpriteBrush(icons.Next32),
+ Brush = new SpriteBrush(icons.Shift64),
Enabled = false,
Visible = false,
Rotation = 180.0f,
@@ -766,7 +766,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[2] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame back (Left Arrow)",
- Brush = new SpriteBrush(icons.ArrowLeft32),
+ Brush = new SpriteBrush(icons.Left32),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -779,7 +779,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackStop = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Stop playback",
- Brush = new SpriteBrush(icons.Stop32),
+ Brush = new SpriteBrush(icons.Stop64),
Visible = false,
Enabled = false,
Parent = playbackButtonsPanel
@@ -792,7 +792,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackPlay = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Play/pause playback (Space)",
- Brush = new SpriteBrush(icons.Play32),
+ Brush = new SpriteBrush(icons.Play64),
Visible = false,
Tag = false, // Set to true if image is set to Pause, false if Play
Parent = playbackButtonsPanel
@@ -805,7 +805,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[3] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame forward (Right Arrow)",
- Brush = new SpriteBrush(icons.ArrowRight32),
+ Brush = new SpriteBrush(icons.Right32),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -816,7 +816,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[4] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Seek to the next keyframe (Page Up)",
- Brush = new SpriteBrush(icons.Next32),
+ Brush = new SpriteBrush(icons.Shift64),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -831,7 +831,7 @@ namespace FlaxEditor.GUI.Timeline
_playbackNavigation[5] = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline end (End)",
- Brush = new SpriteBrush(icons.Step32),
+ Brush = new SpriteBrush(icons.Skip64),
Enabled = false,
Visible = false,
Parent = playbackButtonsPanel
@@ -1189,7 +1189,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
- _playbackPlay.Brush = new SpriteBrush(icons.Play32);
+ _playbackPlay.Brush = new SpriteBrush(icons.Play64);
_playbackPlay.Tag = false;
}
if (_positionHandle != null)
@@ -1215,7 +1215,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
- _playbackPlay.Brush = new SpriteBrush(icons.Pause32);
+ _playbackPlay.Brush = new SpriteBrush(icons.Pause64);
_playbackPlay.Tag = true;
}
if (_positionHandle != null)
@@ -1241,7 +1241,7 @@ namespace FlaxEditor.GUI.Timeline
{
_playbackPlay.Visible = true;
_playbackPlay.Enabled = _canPlayPauseStop;
- _playbackPlay.Brush = new SpriteBrush(icons.Play32);
+ _playbackPlay.Brush = new SpriteBrush(icons.Play64);
_playbackPlay.Tag = false;
}
if (_positionHandle != null)
diff --git a/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs b/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs
index 031226a02..98cb3979f 100644
--- a/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs
+++ b/Source/Editor/GUI/Timeline/Tracks/AudioTrack.cs
@@ -322,7 +322,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(icons.ArrowRight32),
+ Brush = new SpriteBrush(icons.Right32),
Offsets = new Margin(-buttonSize - 2 + _muteCheckbox.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -335,7 +335,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(3),
- Brush = new SpriteBrush(icons.Add48),
+ Brush = new SpriteBrush(icons.Add32),
Offsets = new Margin(-buttonSize - 2 + rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -348,7 +348,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(icons.ArrowLeft32),
+ Brush = new SpriteBrush(icons.Left32),
Offsets = new Margin(-buttonSize - 2 + addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
diff --git a/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs b/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs
index 0c3ab7851..fc9b17601 100644
--- a/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs
+++ b/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs
@@ -695,7 +695,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(icons.Camera32),
+ Brush = new SpriteBrush(icons.Camera64),
Offsets = new Margin(-buttonSize - 2 + _selectActor.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
diff --git a/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs b/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
index 250fb73c3..302570fae 100644
--- a/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
+++ b/Source/Editor/GUI/Timeline/Tracks/MemberTrack.cs
@@ -128,7 +128,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
IsScrollable = false,
Color = Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(icons.ArrowRight32),
+ Brush = new SpriteBrush(icons.Right64),
Offsets = new Margin(-buttonSize - 2 + uiLeft, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -138,9 +138,9 @@ namespace FlaxEditor.GUI.Timeline.Tracks
AutoFocus = true,
AnchorPreset = AnchorPresets.MiddleRight,
IsScrollable = false,
- Color = Style.Current.ForegroundGrey,
+ Color = Style.Current.Foreground,
Margin = new Margin(3),
- Brush = new SpriteBrush(icons.Add48),
+ Brush = new SpriteBrush(icons.Add64),
Offsets = new Margin(-buttonSize - 2 + _rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
@@ -150,9 +150,9 @@ namespace FlaxEditor.GUI.Timeline.Tracks
AutoFocus = true,
AnchorPreset = AnchorPresets.MiddleRight,
IsScrollable = false,
- Color = Style.Current.ForegroundGrey,
+ Color = Style.Current.Foreground,
Margin = new Margin(1),
- Brush = new SpriteBrush(icons.ArrowLeft32),
+ Brush = new SpriteBrush(icons.Left64),
Offsets = new Margin(-buttonSize - 2 + _addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
Parent = this,
};
diff --git a/Source/Editor/History/UndoActionObject.cs b/Source/Editor/History/UndoActionObject.cs
index cac710bff..a87637f4f 100644
--- a/Source/Editor/History/UndoActionObject.cs
+++ b/Source/Editor/History/UndoActionObject.cs
@@ -4,6 +4,8 @@ using System;
using System.Collections.Generic;
using FlaxEditor.Utilities;
using FlaxEngine;
+using Newtonsoft.Json;
+using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor.History
{
@@ -114,6 +116,8 @@ namespace FlaxEditor.History
public object TargetInstance;
}
+ internal static JsonSerializerSettings JsonSettings;
+
// For objects that cannot be referenced in undo action like: FlaxEngine.Object or SceneGraphNode we store them in DataStorage,
// otherwise here:
private readonly object TargetInstance;
@@ -177,6 +181,24 @@ namespace FlaxEditor.History
};
}
+ ///
+ public override DataStorage Data
+ {
+ protected set
+ {
+ // Inject objects typename serialization to prevent data type mismatch when loading from saved state
+ var settings = JsonSettings;
+ if (settings == null)
+ {
+ settings = JsonSerializer.CreateDefaultSettings(false);
+ settings.TypeNameHandling = TypeNameHandling.All;
+ JsonSettings = settings;
+ }
+ _data = JsonConvert.SerializeObject(value, Formatting.Indented, settings);
+ //Editor.Log(_data);
+ }
+ }
+
///
public override string ActionString { get; }
diff --git a/Source/Editor/Managed/ManagedEditor.Internal.cpp b/Source/Editor/Managed/ManagedEditor.Internal.cpp
index 73a65f0f5..a312b38c4 100644
--- a/Source/Editor/Managed/ManagedEditor.Internal.cpp
+++ b/Source/Editor/Managed/ManagedEditor.Internal.cpp
@@ -96,10 +96,9 @@ struct InternalTextureOptions
to->Sprites.EnsureCapacity(count);
for (int32 i = 0; i < count; i++)
{
- Sprite sprite;
+ Sprite& sprite = to->Sprites.AddOne();
sprite.Area = mono_array_get(from->SpriteAreas, Rectangle, i);
sprite.Name = MUtils::ToString(mono_array_get(from->SpriteNames, MonoString*, i));
- to->Sprites.Add(sprite);
}
}
}
@@ -125,7 +124,7 @@ struct InternalTextureOptions
{
const auto domain = mono_domain_get();
int32 count = from->Sprites.Count();
- auto rectClass = Scripting::FindClass("FlaxEngine.Rectangle");
+ auto rectClass = Rectangle::TypeInitializer.GetType().ManagedClass;
ASSERT(rectClass != nullptr);
to->SpriteAreas = mono_array_new(domain, rectClass->GetNative(), count);
to->SpriteNames = mono_array_new(domain, mono_get_string_class(), count);
@@ -521,13 +520,14 @@ public:
return AssetsImportingManager::Create(AssetsImportingManager::CreateVisualScriptTag, outputPath, &baseTypename);
}
- static bool CanImport(MonoString* extensionObj)
+ static MonoString* CanImport(MonoString* extensionObj)
{
String extension;
MUtils::ToString(extensionObj, extension);
if (extension.Length() > 0 && extension[0] == '.')
extension.Remove(0, 1);
- return AssetsImportingManager::GetImporter(extension) != nullptr;
+ const AssetImporter* importer = AssetsImportingManager::GetImporter(extension);
+ return importer ? MUtils::ToString(importer->ResultExtension) : nullptr;
}
static bool Import(MonoString* inputPathObj, MonoString* outputPathObj, void* arg)
diff --git a/Source/Editor/Modules/ContentDatabaseModule.cs b/Source/Editor/Modules/ContentDatabaseModule.cs
index 2d6b179f9..ec71b8564 100644
--- a/Source/Editor/Modules/ContentDatabaseModule.cs
+++ b/Source/Editor/Modules/ContentDatabaseModule.cs
@@ -911,6 +911,8 @@ namespace FlaxEditor.Modules
Proxy.Add(new ParticleSystemProxy());
Proxy.Add(new SceneAnimationProxy());
Proxy.Add(new CSharpScriptProxy());
+ Proxy.Add(new CppAssetProxy());
+ Proxy.Add(new CppStaticClassProxy());
Proxy.Add(new CppScriptProxy());
Proxy.Add(new SceneProxy());
Proxy.Add(new PrefabProxy());
@@ -923,32 +925,34 @@ namespace FlaxEditor.Modules
Proxy.Add(new SkeletonMaskProxy());
Proxy.Add(new GameplayGlobalsProxy());
Proxy.Add(new VisualScriptProxy());
+ Proxy.Add(new LocalizedStringTableProxy());
Proxy.Add(new FileProxy());
Proxy.Add(new SpawnableJsonAssetProxy());
// Settings
- Proxy.Add(new SettingsProxy(typeof(GameSettings)));
- Proxy.Add(new SettingsProxy(typeof(TimeSettings)));
- Proxy.Add(new SettingsProxy(typeof(LayersAndTagsSettings)));
- Proxy.Add(new SettingsProxy(typeof(PhysicsSettings)));
- Proxy.Add(new SettingsProxy(typeof(GraphicsSettings)));
- Proxy.Add(new SettingsProxy(typeof(NavigationSettings)));
- Proxy.Add(new SettingsProxy(typeof(BuildSettings)));
- Proxy.Add(new SettingsProxy(typeof(InputSettings)));
- Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings)));
- Proxy.Add(new SettingsProxy(typeof(UWPPlatformSettings)));
- Proxy.Add(new SettingsProxy(typeof(LinuxPlatformSettings)));
+ Proxy.Add(new SettingsProxy(typeof(GameSettings), Editor.Instance.Icons.GameSettings128));
+ Proxy.Add(new SettingsProxy(typeof(TimeSettings), Editor.Instance.Icons.TimeSettings128));
+ Proxy.Add(new SettingsProxy(typeof(LayersAndTagsSettings), Editor.Instance.Icons.LayersTagsSettings128));
+ Proxy.Add(new SettingsProxy(typeof(PhysicsSettings), Editor.Instance.Icons.PhysicsSettings128));
+ Proxy.Add(new SettingsProxy(typeof(GraphicsSettings), Editor.Instance.Icons.GraphicsSettings128));
+ Proxy.Add(new SettingsProxy(typeof(NavigationSettings), Editor.Instance.Icons.NavigationSettings128));
+ Proxy.Add(new SettingsProxy(typeof(LocalizationSettings), Editor.Instance.Icons.Document128));
+ Proxy.Add(new SettingsProxy(typeof(BuildSettings), Editor.Instance.Icons.BuildSettings128));
+ Proxy.Add(new SettingsProxy(typeof(InputSettings), Editor.Instance.Icons.InputSettings128));
+ Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings), Editor.Instance.Icons.WindowsSettings128));
+ Proxy.Add(new SettingsProxy(typeof(UWPPlatformSettings), Editor.Instance.Icons.UWPSettings128));
+ Proxy.Add(new SettingsProxy(typeof(LinuxPlatformSettings), Editor.Instance.Icons.LinuxSettings128));
var typePS4PlatformSettings = TypeUtils.GetManagedType(GameSettings.PS4PlatformSettingsTypename);
if (typePS4PlatformSettings != null)
- Proxy.Add(new SettingsProxy(typePS4PlatformSettings));
+ Proxy.Add(new SettingsProxy(typePS4PlatformSettings, Editor.Instance.Icons.PlaystationSettings128));
var typeXboxScarlettPlatformSettings = TypeUtils.GetManagedType(GameSettings.XboxScarlettPlatformSettingsTypename);
if (typeXboxScarlettPlatformSettings != null)
- Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings));
- Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings)));
+ Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings, Editor.Instance.Icons.XBoxScarletIcon128));
+ Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings), Editor.Instance.Icons.AndroidSettings128));
var typeSwitchPlatformSettings = TypeUtils.GetManagedType(GameSettings.SwitchPlatformSettingsTypename);
if (typeSwitchPlatformSettings != null)
- Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings));
- Proxy.Add(new SettingsProxy(typeof(AudioSettings)));
+ Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings, Editor.Instance.Icons.Document128));
+ Proxy.Add(new SettingsProxy(typeof(AudioSettings), Editor.Instance.Icons.AudioSettings128));
// Last add generic json (won't override other json proxies)
Proxy.Add(new GenericJsonAssetProxy());
diff --git a/Source/Editor/Modules/ContentEditingModule.cs b/Source/Editor/Modules/ContentEditingModule.cs
index 0d0e65ca9..6d0299a43 100644
--- a/Source/Editor/Modules/ContentEditingModule.cs
+++ b/Source/Editor/Modules/ContentEditingModule.cs
@@ -118,6 +118,25 @@ namespace FlaxEditor.Modules
return false;
}
+ // Check proxy name restrictions
+ if (item is NewItem ni)
+ {
+ if (!ni.Proxy.IsFileNameValid(shortName))
+ {
+ hint = "Name does not follow " + ni.Proxy.Name + " name restrictions !";
+ return false;
+ }
+ }
+ else
+ {
+ var proxy = Editor.ContentDatabase.GetProxy(item);
+ if (proxy != null && !proxy.IsFileNameValid(shortName))
+ {
+ hint = "Name does not follow " + proxy.Name + " name restrictions !";
+ return false;
+ }
+ }
+
// Cache data
string sourcePath = item.Path;
string sourceFolder = System.IO.Path.GetDirectoryName(sourcePath);
diff --git a/Source/Editor/Modules/ContentFindingModule.cs b/Source/Editor/Modules/ContentFindingModule.cs
index 9be15e0d1..45748f7f4 100644
--- a/Source/Editor/Modules/ContentFindingModule.cs
+++ b/Source/Editor/Modules/ContentFindingModule.cs
@@ -309,6 +309,7 @@ namespace FlaxEditor.Modules
{ "FlaxEditor.Content.Settings.InputSettings", "Settings" },
{ "FlaxEditor.Content.Settings.LayersAndTagsSettings", "Settings" },
{ "FlaxEditor.Content.Settings.NavigationSettings", "Settings" },
+ { "FlaxEditor.Content.Settings.LocalizationSettings", "Settings" },
{ "FlaxEditor.Content.Settings.PhysicsSettings", "Settings" },
{ "FlaxEditor.Content.Settings.TimeSettings", "Settings" },
{ "FlaxEditor.Content.Settings.UWPPlatformSettings", "Settings" },
diff --git a/Source/Editor/Modules/ContentImportingModule.cs b/Source/Editor/Modules/ContentImportingModule.cs
index d5ec4b69f..424868fd8 100644
--- a/Source/Editor/Modules/ContentImportingModule.cs
+++ b/Source/Editor/Modules/ContentImportingModule.cs
@@ -193,12 +193,10 @@ namespace FlaxEditor.Modules
var extension = System.IO.Path.GetExtension(inputPath) ?? string.Empty;
// Check if given file extension is a binary asset (.flax files) and can be imported by the engine
- bool isBinaryAsset = Editor.CanImport(extension);
- string outputExtension;
- if (isBinaryAsset)
+ bool isBuilt = Editor.CanImport(extension, out var outputExtension);
+ if (isBuilt)
{
- // Flax it up!
- outputExtension = ".flax";
+ outputExtension = '.' + outputExtension;
if (!targetLocation.CanHaveAssets)
{
@@ -234,7 +232,7 @@ namespace FlaxEditor.Modules
var shortName = System.IO.Path.GetFileNameWithoutExtension(inputPath);
var outputPath = System.IO.Path.Combine(targetLocation.Path, shortName + outputExtension);
- Import(inputPath, outputPath, isBinaryAsset, skipSettingsDialog, settings);
+ Import(inputPath, outputPath, isBuilt, skipSettingsDialog, settings);
}
///
@@ -243,10 +241,10 @@ namespace FlaxEditor.Modules
///
/// The input path.
/// The output path.
- /// True if output file is a binary asset.
+ /// True if use in-built importer (engine backend).
/// True if skip any popup dialogs showing for import options adjusting. Can be used when importing files from code.
/// Import settings to override. Use null to skip this value.
- private void Import(string inputPath, string outputPath, bool isBinaryAsset, bool skipSettingsDialog = false, object settings = null)
+ private void Import(string inputPath, string outputPath, bool isInBuilt, bool skipSettingsDialog = false, object settings = null)
{
lock (_requests)
{
@@ -254,7 +252,7 @@ namespace FlaxEditor.Modules
{
InputPath = inputPath,
OutputPath = outputPath,
- IsBinaryAsset = isBinaryAsset,
+ IsInBuilt = isInBuilt,
SkipSettingsDialog = skipSettingsDialog,
Settings = settings,
});
diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs
index c64ceaa11..c5145a7aa 100644
--- a/Source/Editor/Modules/UIModule.cs
+++ b/Source/Editor/Modules/UIModule.cs
@@ -190,7 +190,7 @@ namespace FlaxEditor.Modules
if (isDuringBreakpointHang)
{
play.Checked = false;
- play.Icon = Editor.Icons.Stop32;
+ play.Icon = Editor.Icons.Stop64;
pause.Enabled = false;
pause.Checked = true;
pause.AutoCheck = false;
@@ -199,7 +199,7 @@ namespace FlaxEditor.Modules
else if (isPlayMode)
{
play.Checked = false;
- play.Icon = Editor.Icons.Stop32;
+ play.Icon = Editor.Icons.Stop64;
pause.Enabled = true;
pause.Checked = Editor.StateMachine.PlayingState.IsPaused;
pause.AutoCheck = false;
@@ -208,7 +208,7 @@ namespace FlaxEditor.Modules
else
{
play.Checked = Editor.Simulation.IsPlayModeRequested;
- play.Icon = Editor.Icons.Play32;
+ play.Icon = Editor.Icons.Play64;
pause.Enabled = canEnterPlayMode;
pause.AutoCheck = true;
step.Enabled = false;
@@ -501,20 +501,20 @@ namespace FlaxEditor.Modules
Parent = mainWindow,
};
- _toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save32, Editor.SaveAll).LinkTooltip("Save all (Ctrl+S)");
+ _toolStripSaveAll = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Save64, Editor.SaveAll).LinkTooltip("Save all (Ctrl+S)");
ToolStrip.AddSeparator();
- _toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo32, Editor.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo32, Editor.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _toolStripUndo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Undo64, Editor.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _toolStripRedo = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Redo64, Editor.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
ToolStrip.AddSeparator();
_toolStripTranslate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Translate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate (1)");
_toolStripRotate = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Rotate32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate (2)");
_toolStripScale = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Scale32, () => Editor.MainTransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale (3)");
ToolStrip.AddSeparator();
- _toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build32, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
+ _toolStripBuildScenes = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Build64, Editor.BuildScenesOrCancel).LinkTooltip("Build scenes data - CSG, navmesh, static lighting, env probes - configurable via Build Actions in editor options (Ctrl+F10)");
ToolStrip.AddSeparator();
- _toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play32, Editor.Simulation.RequestPlayOrStopPlay).LinkTooltip("Start/Stop game (F5)");
- _toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause32, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game(F6)");
- _toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Step32, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
+ _toolStripPlay = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Play64, Editor.Simulation.RequestPlayOrStopPlay).LinkTooltip("Start/Stop game (F5)");
+ _toolStripPause = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Pause64, Editor.Simulation.RequestResumeOrPause).LinkTooltip("Pause/Resume game(F6)");
+ _toolStripStep = (ToolStripButton)ToolStrip.AddButton(Editor.Icons.Skip64, Editor.Simulation.RequestPlayOneFrame).LinkTooltip("Step one frame in game");
UpdateToolstrip();
}
diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs
index 06cff713c..ea42ee99b 100644
--- a/Source/Editor/Options/OptionsModule.cs
+++ b/Source/Editor/Options/OptionsModule.cs
@@ -248,10 +248,11 @@ namespace FlaxEditor.Options
Cross = Editor.Icons.Cross12,
CheckBoxIntermediate = Editor.Icons.CheckBoxIntermediate12,
CheckBoxTick = Editor.Icons.CheckBoxTick12,
- StatusBarSizeGrip = Editor.Icons.StatusBarSizeGrip12,
- Translate = Editor.Icons.Translate16,
- Rotate = Editor.Icons.Rotate16,
- Scale = Editor.Icons.Scale16,
+ StatusBarSizeGrip = Editor.Icons.WindowDrag12,
+ Translate = Editor.Icons.Translate32,
+ Rotate = Editor.Icons.Rotate32,
+ Scale = Editor.Icons.Scale32,
+ Scalar = Editor.Icons.Scalar32,
SharedTooltip = new Tooltip()
};
diff --git a/Source/Editor/SceneGraph/ActorNode.cs b/Source/Editor/SceneGraph/ActorNode.cs
index 017cff3bf..6703c30a0 100644
--- a/Source/Editor/SceneGraph/ActorNode.cs
+++ b/Source/Editor/SceneGraph/ActorNode.cs
@@ -194,7 +194,7 @@ namespace FlaxEditor.SceneGraph
{
get
{
- var scene = _actor.Scene;
+ var scene = _actor ? _actor.Scene : null;
return scene != null ? SceneGraphFactory.FindNode(scene.ID) as SceneNode : null;
}
}
@@ -235,7 +235,6 @@ namespace FlaxEditor.SceneGraph
{
if (!(value is ActorNode))
throw new InvalidOperationException("ActorNode can have only ActorNode as a parent node.");
-
base.ParentNode = value;
}
}
@@ -289,6 +288,13 @@ namespace FlaxEditor.SceneGraph
{
}
+ ///
+ /// Action called after pasting actor in editor.
+ ///
+ public virtual void PostPaste()
+ {
+ }
+
///
protected override void OnParentChanged()
{
@@ -299,6 +305,7 @@ namespace FlaxEditor.SceneGraph
// (eg. we build new node for spawned actor and link it to the game)
if (_treeNode.Parent != null && !_treeNode.Parent.IsLayoutLocked)
{
+ _treeNode.IndexInParent = _actor.OrderInParent;
_treeNode.Parent.SortChildren();
// Update UI
diff --git a/Source/Editor/SceneGraph/Actors/UIControlNode.cs b/Source/Editor/SceneGraph/Actors/UIControlNode.cs
index b3f8f5d09..c4f7d1c17 100644
--- a/Source/Editor/SceneGraph/Actors/UIControlNode.cs
+++ b/Source/Editor/SceneGraph/Actors/UIControlNode.cs
@@ -25,5 +25,20 @@ namespace FlaxEditor.SceneGraph.Actors
if (Actor is UIControl uiControl)
DebugDraw.DrawWireBox(uiControl.Bounds, Color.BlueViolet);
}
+
+ ///
+ public override void PostPaste()
+ {
+ base.PostPaste();
+
+ var control = ((UIControl)Actor).Control;
+ if (control != null)
+ {
+ if (control.Parent != null)
+ control.Parent.PerformLayout();
+ else
+ control.PerformLayout();
+ }
+ }
}
}
diff --git a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
index 7b4b35ed1..5e2792dc4 100644
--- a/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
+++ b/Source/Editor/SceneGraph/GUI/ActorTreeNode.cs
@@ -86,6 +86,10 @@ namespace FlaxEditor.SceneGraph.GUI
}
parent.SortChildren();
}
+ else if (Actor)
+ {
+ _orderInParent = Actor.OrderInParent;
+ }
}
internal void OnNameChanged()
@@ -537,7 +541,7 @@ namespace FlaxEditor.SceneGraph.GUI
var customAction = targetActor.HasPrefabLink ? new ReparentAction(targetActor) : null;
using (new UndoBlock(ActorNode.Root.Undo, targetActor, "Change actor parent", customAction))
{
- targetActor.SetParent(newParent, worldPositionLock);
+ targetActor.SetParent(newParent, worldPositionLock, true);
targetActor.OrderInParent = newOrder;
}
}
@@ -550,7 +554,7 @@ namespace FlaxEditor.SceneGraph.GUI
for (int i = 0; i < targetActors.Count; i++)
{
var targetActor = targetActors[i];
- targetActor.SetParent(newParent, worldPositionLock);
+ targetActor.SetParent(newParent, worldPositionLock, true);
targetActor.OrderInParent = newOrder;
}
}
diff --git a/Source/Editor/SceneGraph/SceneGraphNode.cs b/Source/Editor/SceneGraph/SceneGraphNode.cs
index 76327918d..bc8fe84aa 100644
--- a/Source/Editor/SceneGraph/SceneGraphNode.cs
+++ b/Source/Editor/SceneGraph/SceneGraphNode.cs
@@ -112,18 +112,9 @@ namespace FlaxEditor.SceneGraph
{
if (parentNode != value)
{
- if (parentNode != null)
- {
- parentNode.ChildNodes.Remove(this);
- }
-
+ parentNode?.ChildNodes.Remove(this);
parentNode = value;
-
- if (parentNode != null)
- {
- parentNode.ChildNodes.Add(this);
- }
-
+ parentNode?.ChildNodes.Add(this);
OnParentChanged();
}
}
@@ -374,6 +365,7 @@ namespace FlaxEditor.SceneGraph
///
/// Gets or sets the node state.
///
+ [NoSerialize]
public virtual StateData State
{
get => throw new NotImplementedException();
diff --git a/Source/Editor/Scripting/ScriptsBuilder.cpp b/Source/Editor/Scripting/ScriptsBuilder.cpp
index 00a93b66c..71323dc34 100644
--- a/Source/Editor/Scripting/ScriptsBuilder.cpp
+++ b/Source/Editor/Scripting/ScriptsBuilder.cpp
@@ -9,6 +9,7 @@
#include "Engine/Core/Types/StringBuilder.h"
#include "Engine/Debug/Exceptions/FileNotFoundException.h"
#include "Engine/Engine/Engine.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Platform/FileSystemWatcher.h"
#include "Engine/Threading/ThreadPool.h"
diff --git a/Source/Editor/Surface/Archetypes/Function.cs b/Source/Editor/Surface/Archetypes/Function.cs
index a47b41a82..4e017248a 100644
--- a/Source/Editor/Surface/Archetypes/Function.cs
+++ b/Source/Editor/Surface/Archetypes/Function.cs
@@ -576,7 +576,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < _parameters.Length; i++)
{
writer.Write(_parameters[i].Name); // Parameter name
- Utilities.Utils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
+ Utilities.VariantUtils.WriteVariantType(writer, TypeUtils.GetType(_parameters[i].Type)); // Box type
}
SetValue(2, stream.ToArray());
}
@@ -594,7 +594,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < parametersCount; i++)
{
var parameterName = reader.ReadString(); // Parameter name
- var boxType = Utilities.Utils.ReadVariantType(reader); // Box type
+ var boxType = Utilities.VariantUtils.ReadVariantType(reader); // Box type
MakeBox(i + 1, parameterName, boxType);
}
}
@@ -778,14 +778,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static
- signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
+ signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
param.Name = Utilities.Utils.ReadStr(reader, 11); // Parameter name
- param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
+ param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out
}
}
@@ -799,14 +799,14 @@ namespace FlaxEditor.Surface.Archetypes
{
reader.ReadByte(); // Version
signature.IsStatic = reader.ReadBoolean(); // Is Static
- signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return type
+ signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return type
var parametersCount = reader.ReadInt32(); // Parameters count
signature.Params = parametersCount != 0 ? new SignatureParamInfo[parametersCount] : Utils.GetEmptyArray();
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref signature.Params[i];
param.Name = reader.ReadString(); // Parameter name
- param.Type = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
+ param.Type = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
param.IsOut = reader.ReadByte() != 0; // Is parameter out
}
}
@@ -823,13 +823,13 @@ namespace FlaxEditor.Surface.Archetypes
{
writer.Write((byte)4); // Version
writer.Write(methodInfo.IsStatic); // Is Static
- Utilities.Utils.WriteVariantType(writer, methodInfo.ValueType); // Return type
+ Utilities.VariantUtils.WriteVariantType(writer, methodInfo.ValueType); // Return type
writer.Write(parameters.Length); // Parameters count
for (int i = 0; i < parameters.Length; i++)
{
ref var param = ref parameters[i];
Utilities.Utils.WriteStr(writer, param.Name, 11); // Parameter name
- Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
+ Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)(param.IsOut ? 1 : 0)); // Is parameter out
}
return stream.ToArray();
@@ -1434,14 +1434,14 @@ namespace FlaxEditor.Surface.Archetypes
if (_signature.IsVirtual)
flags |= Flags.Virtual;
writer.Write((byte)flags); // Flags
- Utilities.Utils.WriteVariantType(writer, _signature.ReturnType); // Return Type
+ Utilities.VariantUtils.WriteVariantType(writer, _signature.ReturnType); // Return Type
var parametersCount = _signature.Parameters?.Length ?? 0;
writer.Write(parametersCount); // Parameters count
for (int i = 0; i < parametersCount; i++)
{
ref var param = ref _signature.Parameters[i];
Utilities.Utils.WriteStrAnsi(writer, param.Name, 13); // Parameter name
- Utilities.Utils.WriteVariantType(writer, param.Type); // Parameter type
+ Utilities.VariantUtils.WriteVariantType(writer, param.Type); // Parameter type
writer.Write((byte)0); // Is parameter out
writer.Write((byte)0); // Has default value
}
@@ -1470,13 +1470,13 @@ namespace FlaxEditor.Surface.Archetypes
var flags = (Flags)reader.ReadByte(); // Flags
_signature.IsStatic = (flags & Flags.Static) == Flags.Static;
_signature.IsVirtual = (flags & Flags.Virtual) == Flags.Virtual;
- _signature.ReturnType = Utilities.Utils.ReadVariantScriptType(reader); // Return Type
+ _signature.ReturnType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Return Type
var parametersCount = reader.ReadInt32(); // Parameters count
_signature.Parameters = new Parameter[parametersCount];
for (int i = 0; i < parametersCount; i++)
{
var paramName = Utilities.Utils.ReadStrAnsi(reader, 13); // Parameter name
- var paramType = Utilities.Utils.ReadVariantScriptType(reader); // Parameter type
+ var paramType = Utilities.VariantUtils.ReadVariantScriptType(reader); // Parameter type
var isOut = reader.ReadByte() != 0; // Is parameter out
var hasDefaultValue = reader.ReadByte() != 0; // Has default value
_signature.Parameters[i] = new Parameter
@@ -1993,7 +1993,7 @@ namespace FlaxEditor.Surface.Archetypes
}
else if (_isBind)
{
- _helperButton.Brush = new SpriteBrush(Editor.Instance.Icons.Add48);
+ _helperButton.Brush = new SpriteBrush(Editor.Instance.Icons.Add64);
_helperButton.Color = Color.Red;
_helperButton.TooltipText = "Add new handler function and bind it to this event";
_helperButton.Enabled = _signature != null;
diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs
index 95f503338..0e9fa4ff0 100644
--- a/Source/Editor/Surface/Archetypes/Packing.cs
+++ b/Source/Editor/Surface/Archetypes/Packing.cs
@@ -171,7 +171,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
Utilities.Utils.WriteStr(writer, fields[i].Name, 11); // Field type
- Utilities.Utils.WriteVariantType(writer, fields[i].ValueType); // Field type
+ Utilities.VariantUtils.WriteVariantType(writer, fields[i].ValueType); // Field type
}
Values[1] = stream.ToArray();
}
@@ -188,7 +188,7 @@ namespace FlaxEditor.Surface.Archetypes
for (int i = 0; i < fieldsLength; i++)
{
var fieldName = Utilities.Utils.ReadStr(reader, 11); // Field name
- var fieldType = Utilities.Utils.ReadVariantType(reader); // Field type
+ var fieldType = Utilities.VariantUtils.ReadVariantType(reader); // Field type
MakeBox(i + 1, fieldName, new ScriptType(fieldType));
}
}
diff --git a/Source/Editor/Surface/Archetypes/Tools.cs b/Source/Editor/Surface/Archetypes/Tools.cs
index 15f2b15b8..005af20cc 100644
--- a/Source/Editor/Surface/Archetypes/Tools.cs
+++ b/Source/Editor/Surface/Archetypes/Tools.cs
@@ -104,7 +104,7 @@ namespace FlaxEditor.Surface.Archetypes
color *= 1.3f;
color.A = 1.0f;
var icons = Editor.Instance.Icons;
- var icon = isSelected ? icons.VisjectArrowClose : icons.VisjectArrowOpen;
+ var icon = isSelected ? icons.VisjectArrowClosed32 : icons.VisjectArrowOpen32;
Render2D.PushTransform(ref arrowTransform);
Render2D.DrawSprite(icon, arrowRect, color);
diff --git a/Source/Editor/Surface/Elements/EnumValue.cs b/Source/Editor/Surface/Elements/EnumValue.cs
index a66031f35..dbd1620ab 100644
--- a/Source/Editor/Surface/Elements/EnumValue.cs
+++ b/Source/Editor/Surface/Elements/EnumValue.cs
@@ -32,7 +32,7 @@ namespace FlaxEditor.Surface.Elements
Width = archetype.Size.X;
ParentNode = parentNode;
Archetype = archetype;
- Value = (ulong)(int)ParentNode.Values[Archetype.ValueIndex];
+ Value = (int)ParentNode.Values[Archetype.ValueIndex];
}
///
diff --git a/Source/Editor/Surface/Elements/InputBox.cs b/Source/Editor/Surface/Elements/InputBox.cs
index ea6e9e34a..c830cf499 100644
--- a/Source/Editor/Surface/Elements/InputBox.cs
+++ b/Source/Editor/Surface/Elements/InputBox.cs
@@ -9,6 +9,8 @@ using FlaxEditor.GUI.Input;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
+using Newtonsoft.Json;
+using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor.Surface.Elements
{
@@ -981,6 +983,121 @@ namespace FlaxEditor.Surface.Elements
}
}
+ ///
+ public override bool OnMouseUp(Vector2 location, MouseButton button)
+ {
+ if (button == MouseButton.Right && Archetype.ValueIndex != -1)
+ {
+ var menu = new FlaxEditor.GUI.ContextMenu.ContextMenu();
+ menu.AddButton("Copy value", OnCopyValue);
+ var paste = menu.AddButton("Paste value", OnPasteValue);
+ try
+ {
+ GetClipboardValue(out _, false);
+ }
+ catch
+ {
+ paste.Enabled = false;
+ }
+
+ menu.Show(this, location);
+ return true;
+ }
+
+ return base.OnMouseUp(location, button);
+ }
+
+ private bool GetClipboardValue(out object result, bool deserialize)
+ {
+ result = null;
+ var text = Clipboard.Text;
+ if (string.IsNullOrEmpty(text))
+ return false;
+
+ object obj;
+ var type = CurrentType;
+ if (new ScriptType(typeof(FlaxEngine.Object)).IsAssignableFrom(type))
+ {
+ // Object reference
+ if (text.Length != 32)
+ return false;
+ JsonSerializer.ParseID(text, out var id);
+ obj = FlaxEngine.Object.Find(ref id);
+ }
+ else
+ {
+ // Default
+ obj = JsonConvert.DeserializeObject(text, TypeUtils.GetType(type), JsonSerializer.Settings);
+ }
+
+ if (obj == null || type.IsInstanceOfType(obj))
+ {
+ result = obj;
+ return true;
+ }
+
+ return false;
+ }
+
+ private void OnCopyValue()
+ {
+ var value = ParentNode.Values[Archetype.ValueIndex];
+
+ try
+ {
+ string text;
+ if (value == null)
+ {
+ // Missing value
+ var type = CurrentType;
+ if (type.Type == typeof(bool))
+ text = "false";
+ else if (type.Type == typeof(byte) || type.Type == typeof(sbyte) || type.Type == typeof(char) || type.Type == typeof(short) || type.Type == typeof(ushort) || type.Type == typeof(int) || type.Type == typeof(uint) || type.Type == typeof(long) || type.Type == typeof(ulong))
+ text = "0";
+ else if (type.Type == typeof(float) || type.Type == typeof(double))
+ text = "0.0";
+ else if (type.Type == typeof(Vector2) || type.Type == typeof(Vector3) || type.Type == typeof(Vector4) || type.Type == typeof(Color))
+ text = JsonSerializer.Serialize(TypeUtils.GetDefaultValue(type));
+ else if (type.Type == typeof(string))
+ text = "";
+ else
+ text = "null";
+ }
+ else if (value is FlaxEngine.Object asObject)
+ {
+ // Object reference
+ text = JsonSerializer.GetStringID(asObject);
+ }
+ else
+ {
+ // Default
+ text = JsonSerializer.Serialize(value);
+ }
+ Clipboard.Text = text;
+ }
+ catch (Exception ex)
+ {
+ Editor.LogWarning(ex);
+ Editor.LogError("Cannot copy property. See log for more info.");
+ }
+ }
+
+ private void OnPasteValue()
+ {
+ try
+ {
+ if (GetClipboardValue(out var value, true))
+ {
+ ParentNode.SetValue(Archetype.ValueIndex, value);
+ }
+ }
+ catch (Exception ex)
+ {
+ Editor.LogWarning(ex);
+ Editor.LogError("Cannot paste property value. See log for more info.");
+ }
+ }
+
///
/// Creates the default value editor control.
///
diff --git a/Source/Editor/Surface/SurfaceStyle.cs b/Source/Editor/Surface/SurfaceStyle.cs
index 18de19118..db25b9f09 100644
--- a/Source/Editor/Surface/SurfaceStyle.cs
+++ b/Source/Editor/Surface/SurfaceStyle.cs
@@ -224,10 +224,10 @@ namespace FlaxEditor.Surface
},
Icons =
{
- BoxOpen = editor.Icons.VisjectBoxOpen,
- BoxClose = editor.Icons.VisjectBoxClose,
- ArrowOpen = editor.Icons.VisjectArrowOpen,
- ArrowClose = editor.Icons.VisjectArrowClose,
+ BoxOpen = editor.Icons.VisjectBoxOpen32,
+ BoxClose = editor.Icons.VisjectBoxClosed32,
+ ArrowOpen = editor.Icons.VisjectArrowOpen32,
+ ArrowClose = editor.Icons.VisjectArrowClosed32,
},
Background = editor.UI.VisjectSurfaceBackground,
};
diff --git a/Source/Editor/Surface/VisjectSurfaceWindow.cs b/Source/Editor/Surface/VisjectSurfaceWindow.cs
index b5c502ba5..810f125ae 100644
--- a/Source/Editor/Surface/VisjectSurfaceWindow.cs
+++ b/Source/Editor/Surface/VisjectSurfaceWindow.cs
@@ -759,12 +759,12 @@ namespace FlaxEditor.Surface
_propertiesEditor.Modified += OnPropertyEdited;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.PageScale32, ShowWholeGraph).LinkTooltip("Show whole graph");
+ _toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
diff --git a/Source/Editor/Undo/Actions/PasteActorsAction.cs b/Source/Editor/Undo/Actions/PasteActorsAction.cs
index c65aa6bf0..c77feb71d 100644
--- a/Source/Editor/Undo/Actions/PasteActorsAction.cs
+++ b/Source/Editor/Undo/Actions/PasteActorsAction.cs
@@ -140,22 +140,27 @@ namespace FlaxEditor.Actions
for (int i = 0; i < nodeParents.Count; i++)
{
- // Fix name collisions (only for parents)
var node = nodeParents[i];
var parent = node.Actor?.Parent;
if (parent != null)
{
+ // Fix name collisions
string name = node.Name;
Actor[] children = parent.Children;
if (children.Any(x => x.Name == name))
{
- // Generate new name
node.Actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
}
}
Editor.Instance.Scene.MarkSceneEdited(node.ParentScene);
}
+
+ for (int i = 0; i < nodeParents.Count; i++)
+ {
+ var node = nodeParents[i];
+ node.PostPaste();
+ }
}
///
diff --git a/Source/Editor/Undo/UndoActionBase.cs b/Source/Editor/Undo/UndoActionBase.cs
index 5de052a45..6648096c6 100644
--- a/Source/Editor/Undo/UndoActionBase.cs
+++ b/Source/Editor/Undo/UndoActionBase.cs
@@ -4,7 +4,6 @@ using System;
using FlaxEditor.SceneGraph;
using FlaxEngine;
using Newtonsoft.Json;
-using JsonSerializer = FlaxEngine.Json.JsonSerializer;
namespace FlaxEditor
{
@@ -28,7 +27,6 @@ namespace FlaxEditor
var id = Guid.Parse((string)reader.Value);
return SceneGraphFactory.FindNode(id);
}
-
return null;
}
@@ -56,19 +54,11 @@ namespace FlaxEditor
///
/// Gets or sets the serialized undo data.
///
- ///
- /// The data.
- ///
[NoSerialize]
- public TData Data
+ public virtual TData Data
{
- get => JsonConvert.DeserializeObject(_data, JsonSerializer.Settings);
- protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, JsonSerializer.Settings);
- /*protected set
- {
- _data = JsonConvert.SerializeObject(value, Formatting.Indented, JsonSerializer.Settings);
- Debug.Info(_data);
- }*/
+ get => JsonConvert.DeserializeObject(_data, FlaxEngine.Json.JsonSerializer.Settings);
+ protected set => _data = JsonConvert.SerializeObject(value, Formatting.None, FlaxEngine.Json.JsonSerializer.Settings);
}
///
diff --git a/Source/Editor/Utilities/EditorUtilities.cpp b/Source/Editor/Utilities/EditorUtilities.cpp
index aa26388c1..85d409b92 100644
--- a/Source/Editor/Utilities/EditorUtilities.cpp
+++ b/Source/Editor/Utilities/EditorUtilities.cpp
@@ -1,6 +1,7 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "EditorUtilities.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Platform/File.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Core/Log.h"
diff --git a/Source/Editor/Utilities/Utils.cs b/Source/Editor/Utilities/Utils.cs
index 6c7aa86d7..3eab59f80 100644
--- a/Source/Editor/Utilities/Utils.cs
+++ b/Source/Editor/Utilities/Utils.cs
@@ -2,15 +2,15 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
+using FlaxEditor.GUI.ContextMenu;
+using FlaxEditor.GUI.Tree;
using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
-using Newtonsoft.Json;
namespace FlaxEditor.Utilities
{
@@ -29,50 +29,6 @@ namespace FlaxEditor.Utilities
"PB"
};
- internal enum VariantType
- {
- Null = 0,
- Void,
-
- Bool,
- Int,
- Uint,
- Int64,
- Uint64,
- Float,
- Double,
- Pointer,
-
- String,
- Object,
- Structure,
- Asset,
- Blob,
- Enum,
-
- Vector2,
- Vector3,
- Vector4,
- Color,
- Guid,
- BoundingBox,
- BoundingSphere,
- Quaternion,
- Transform,
- Rectangle,
- Ray,
- Matrix,
-
- Array,
- Dictionary,
- ManagedObject,
- Typename,
-
- Int2,
- Int3,
- Int4
- }
-
///
/// The name of the Flax Engine C# assembly name.
///
@@ -403,157 +359,6 @@ namespace FlaxEditor.Utilities
stream.Write(bytes);
}
- internal static VariantType ToVariantType(this Type type)
- {
- VariantType variantType;
- if (type == null)
- variantType = VariantType.Null;
- else if (type == typeof(void))
- variantType = VariantType.Void;
- else if (type == typeof(bool))
- variantType = VariantType.Bool;
- else if (type == typeof(int))
- variantType = VariantType.Int;
- else if (type == typeof(uint))
- variantType = VariantType.Uint;
- else if (type == typeof(long))
- variantType = VariantType.Int64;
- else if (type == typeof(ulong))
- variantType = VariantType.Uint64;
- else if (type.IsEnum)
- variantType = VariantType.Enum;
- else if (type == typeof(float))
- variantType = VariantType.Float;
- else if (type == typeof(double))
- variantType = VariantType.Double;
- else if (type == typeof(IntPtr))
- variantType = VariantType.Pointer;
- else if (type == typeof(string))
- variantType = VariantType.String;
- else if (type == typeof(Type) || type == typeof(ScriptType))
- variantType = VariantType.Typename;
- else if (typeof(Asset).IsAssignableFrom(type))
- variantType = VariantType.Asset;
- else if (typeof(FlaxEngine.Object).IsAssignableFrom(type))
- variantType = VariantType.Object;
- else if (type == typeof(BoundingBox))
- variantType = VariantType.BoundingBox;
- else if (type == typeof(Transform))
- variantType = VariantType.Transform;
- else if (type == typeof(Ray))
- variantType = VariantType.Ray;
- else if (type == typeof(Matrix))
- variantType = VariantType.Matrix;
- else if (type == typeof(Vector2))
- variantType = VariantType.Vector2;
- else if (type == typeof(Vector3))
- variantType = VariantType.Vector3;
- else if (type == typeof(Vector4))
- variantType = VariantType.Vector4;
- else if (type == typeof(Int2))
- variantType = VariantType.Int2;
- else if (type == typeof(Int3))
- variantType = VariantType.Int3;
- else if (type == typeof(Int4))
- variantType = VariantType.Int4;
- else if (type == typeof(Color))
- variantType = VariantType.Color;
- else if (type == typeof(Guid))
- variantType = VariantType.Guid;
- else if (type == typeof(Quaternion))
- variantType = VariantType.Quaternion;
- else if (type == typeof(Rectangle))
- variantType = VariantType.Rectangle;
- else if (type == typeof(BoundingSphere))
- variantType = VariantType.BoundingSphere;
- else if (type.IsValueType)
- variantType = VariantType.Structure;
- else if (type == typeof(byte[]))
- variantType = VariantType.Blob;
- else if (type == typeof(object[]))
- variantType = VariantType.Array;
- else if (type == typeof(Dictionary
public bool DrawDebugDraw = true;
+ ///
+ /// Gets the debug draw data for the viewport.
+ ///
+ public ViewportDebugDrawData DebugDrawData => _debugDrawData;
+
///
/// Gets or sets a value indicating whether show navigation mesh.
///
@@ -219,7 +224,7 @@ namespace FlaxEditor.Viewport
// Transform space widget
var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.World16, null, true)
+ var transformSpaceToggle = new ViewportWidgetButton(string.Empty, editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
TooltipText = "Gizmo transform space (world or local)",
@@ -230,7 +235,7 @@ namespace FlaxEditor.Viewport
// Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleStep16, null, true)
+ var enableScaleSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.ScaleSnap32, null, true)
{
Checked = TransformGizmo.ScaleSnapEnabled,
TooltipText = "Enable scale snapping",
@@ -257,7 +262,7 @@ namespace FlaxEditor.Viewport
// Rotation snapping widget
var rotateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableRotateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.RotateStep16, null, true)
+ var enableRotateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.RotateSnap32, null, true)
{
Checked = TransformGizmo.RotationSnapEnabled,
TooltipText = "Enable rotation snapping",
@@ -284,7 +289,7 @@ namespace FlaxEditor.Viewport
// Translation snapping widget
var translateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.Grid16, null, true)
+ var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, editor.Icons.Grid32, null, true)
{
Checked = TransformGizmo.TranslationSnapEnable,
TooltipText = "Enable position snapping",
@@ -311,7 +316,7 @@ namespace FlaxEditor.Viewport
// Gizmo mode widget
var gizmoMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- _gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate16, null, true)
+ _gizmoModeTranslate = new ViewportWidgetButton(string.Empty, editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
TooltipText = "Translate gizmo mode",
@@ -319,14 +324,14 @@ namespace FlaxEditor.Viewport
Parent = gizmoMode
};
_gizmoModeTranslate.Toggled += OnGizmoModeToggle;
- _gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate16, null, true)
+ _gizmoModeRotate = new ViewportWidgetButton(string.Empty, editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
TooltipText = "Rotate gizmo mode",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
- _gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale16, null, true)
+ _gizmoModeScale = new ViewportWidgetButton(string.Empty, editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
TooltipText = "Scale gizmo mode",
@@ -389,10 +394,11 @@ namespace FlaxEditor.Viewport
return;
// Create actor
+ var parent = Level.GetScene(0);
var actor = new Camera
{
StaticFlags = StaticFlags.None,
- Name = "Camera",
+ Name = StringUtils.IncrementNameNumber("Camera", x => parent.GetChild(x) == null),
Transform = ViewTransform,
NearPlane = NearPlane,
FarPlane = FarPlane,
@@ -402,7 +408,7 @@ namespace FlaxEditor.Viewport
};
// Spawn
- Editor.Instance.SceneEditing.Spawn(actor);
+ Editor.Instance.SceneEditing.Spawn(actor, parent);
}
private void OnBegin(RenderTask task, GPUContext context)
@@ -877,6 +883,8 @@ namespace FlaxEditor.Viewport
private void Spawn(Actor actor, ref Vector3 hitLocation)
{
actor.Position = PostProcessSpawnedActorLocation(actor, ref hitLocation);
+ var parent = actor.Parent ?? Level.GetScene(0);
+ actor.Name = StringUtils.IncrementNameNumber(actor.Name, x => parent.GetChild(x) == null);
Editor.Instance.SceneEditing.Spawn(actor);
Focus();
}
diff --git a/Source/Editor/Viewport/PrefabWindowViewport.cs b/Source/Editor/Viewport/PrefabWindowViewport.cs
index d59ebb977..6483700b6 100644
--- a/Source/Editor/Viewport/PrefabWindowViewport.cs
+++ b/Source/Editor/Viewport/PrefabWindowViewport.cs
@@ -118,7 +118,7 @@ namespace FlaxEditor.Viewport
// Transform space widget
var transformSpaceWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.World16, null, true)
+ var transformSpaceToggle = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Globe32, null, true)
{
Checked = TransformGizmo.ActiveTransformSpace == TransformGizmoBase.TransformSpace.World,
TooltipText = "Gizmo transform space (world or local)",
@@ -129,7 +129,7 @@ namespace FlaxEditor.Viewport
// Scale snapping widget
var scaleSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableScaleSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.ScaleStep16, null, true)
+ var enableScaleSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.ScaleSnap32, null, true)
{
Checked = TransformGizmo.ScaleSnapEnabled,
TooltipText = "Enable scale snapping",
@@ -156,7 +156,7 @@ namespace FlaxEditor.Viewport
// Rotation snapping widget
var rotateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableRotateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.RotateStep16, null, true)
+ var enableRotateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.RotateSnap32, null, true)
{
Checked = TransformGizmo.RotationSnapEnabled,
TooltipText = "Enable rotation snapping",
@@ -183,7 +183,7 @@ namespace FlaxEditor.Viewport
// Translation snapping widget
var translateSnappingWidget = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Grid16, null, true)
+ var enableTranslateSnapping = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Grid32, null, true)
{
Checked = TransformGizmo.TranslationSnapEnable,
TooltipText = "Enable position snapping",
@@ -210,7 +210,7 @@ namespace FlaxEditor.Viewport
// Gizmo mode widget
var gizmoMode = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight);
- _gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate16, null, true)
+ _gizmoModeTranslate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Translate32, null, true)
{
Tag = TransformGizmoBase.Mode.Translate,
TooltipText = "Translate gizmo mode",
@@ -218,14 +218,14 @@ namespace FlaxEditor.Viewport
Parent = gizmoMode
};
_gizmoModeTranslate.Toggled += OnGizmoModeToggle;
- _gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate16, null, true)
+ _gizmoModeRotate = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Rotate32, null, true)
{
Tag = TransformGizmoBase.Mode.Rotate,
TooltipText = "Rotate gizmo mode",
Parent = gizmoMode
};
_gizmoModeRotate.Toggled += OnGizmoModeToggle;
- _gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale16, null, true)
+ _gizmoModeScale = new ViewportWidgetButton(string.Empty, window.Editor.Icons.Scale32, null, true)
{
Tag = TransformGizmoBase.Mode.Scale,
TooltipText = "Scale gizmo mode",
diff --git a/Source/Editor/Windows/AboutDialog.cs b/Source/Editor/Windows/AboutDialog.cs
index bb320fb87..5e43b408b 100644
--- a/Source/Editor/Windows/AboutDialog.cs
+++ b/Source/Editor/Windows/AboutDialog.cs
@@ -34,7 +34,7 @@ namespace FlaxEditor.Windows
{
Image icon = new Image(4, 4, 80, 80)
{
- Brush = new SpriteBrush(Editor.Instance.Icons.Logo128),
+ Brush = new SpriteBrush(Editor.Instance.Icons.FlaxLogo128),
Parent = this
};
var nameLabel = new Label(icon.Right + 10, icon.Top, 200, 34)
@@ -131,6 +131,7 @@ namespace FlaxEditor.Windows
"LZ4 Library - Copyright (c) Yann Collet. All rights reserved.",
"fmt - www.fmtlib.net",
"minimp3 - www.github.com/lieff/minimp3",
+ "Tracy Profiler - www.github.com/wolfpld/tracy",
"Ogg and Vorbis - Xiph.org Foundation",
"OpenAL Soft - www.github.com/kcat/openal-soft",
"OpenFBX - www.github.com/nem0/OpenFBX",
diff --git a/Source/Editor/Windows/Assets/AnimationGraphFunctionWindow.cs b/Source/Editor/Windows/Assets/AnimationGraphFunctionWindow.cs
index 439f61c9f..4be79d36d 100644
--- a/Source/Editor/Windows/Assets/AnimationGraphFunctionWindow.cs
+++ b/Source/Editor/Windows/Assets/AnimationGraphFunctionWindow.cs
@@ -33,7 +33,7 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
// Navigation bar
_navigationBar = new NavigationBar
diff --git a/Source/Editor/Windows/Assets/AnimationGraphWindow.cs b/Source/Editor/Windows/Assets/AnimationGraphWindow.cs
index f25b51612..634202061 100644
--- a/Source/Editor/Windows/Assets/AnimationGraphWindow.cs
+++ b/Source/Editor/Windows/Assets/AnimationGraphWindow.cs
@@ -251,9 +251,9 @@ namespace FlaxEditor.Windows.Assets
_surface.ContextChanged += OnSurfaceContextChanged;
// Toolstrip
- _toolstrip.AddButton(editor.Icons.Bone32, () => _preview.ShowNodes = !_preview.ShowNodes).SetAutoCheck(true).LinkTooltip("Show animated model nodes debug view");
+ _toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).SetAutoCheck(true).LinkTooltip("Show animated model nodes debug view");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/anim-graph/index.html")).LinkTooltip("See documentation to learn more");
// Debug picker
var debugPickerContainer = new ContainerControl();
diff --git a/Source/Editor/Windows/Assets/AnimationWindow.cs b/Source/Editor/Windows/Assets/AnimationWindow.cs
index fde6ec3cb..5665a87ce 100644
--- a/Source/Editor/Windows/Assets/AnimationWindow.cs
+++ b/Source/Editor/Windows/Assets/AnimationWindow.cs
@@ -150,12 +150,12 @@ namespace FlaxEditor.Windows.Assets
_propertiesPresenter.Modified += MarkAsEdited;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/animation/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/animation/index.html")).LinkTooltip("See documentation to learn more");
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
diff --git a/Source/Editor/Windows/Assets/AssetEditorWindow.cs b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
index 8ad655d01..94b78db7e 100644
--- a/Source/Editor/Windows/Assets/AssetEditorWindow.cs
+++ b/Source/Editor/Windows/Assets/AssetEditorWindow.cs
@@ -53,7 +53,7 @@ namespace FlaxEditor.Windows.Assets
{
Parent = this
};
- _toolstrip.AddButton(editor.Icons.Find32, () => Editor.Windows.ContentWin.Select(_item)).LinkTooltip("Show and select in Content Window");
+ _toolstrip.AddButton(editor.Icons.Search64, () => Editor.Windows.ContentWin.Select(_item)).LinkTooltip("Show and select in Content Window");
InputActions.Add(options => options.Save, Save);
diff --git a/Source/Editor/Windows/Assets/AudioClipWindow.cs b/Source/Editor/Windows/Assets/AudioClipWindow.cs
index 1d6850200..cce6985dc 100644
--- a/Source/Editor/Windows/Assets/AudioClipWindow.cs
+++ b/Source/Editor/Windows/Assets/AudioClipWindow.cs
@@ -152,12 +152,12 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_properties);
// Toolstrip
- _toolstrip.AddButton(Editor.Icons.Import32, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
+ _toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
- _playButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Play32, OnPlay).LinkTooltip("Play/stop audio");
- _pauseButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Pause32, OnPause).LinkTooltip("Pause audio");
+ _playButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Play64, OnPlay).LinkTooltip("Play/stop audio");
+ _pauseButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Pause64, OnPause).LinkTooltip("Pause audio");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/audio/audio-clip.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/audio/audio-clip.html")).LinkTooltip("See documentation to learn more");
}
private void OnPlay()
@@ -244,7 +244,7 @@ namespace FlaxEditor.Windows.Assets
{
base.UpdateToolstrip();
- _playButton.Icon = _previewSource && _previewSource.State == AudioSource.States.Playing ? Editor.Icons.Stop32 : Editor.Icons.Play32;
+ _playButton.Icon = _previewSource && _previewSource.State == AudioSource.States.Playing ? Editor.Icons.Stop64 : Editor.Icons.Play64;
_pauseButton.Enabled = _previewSource && _previewSource.State == AudioSource.States.Playing;
}
diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs
index 0ff3f86e7..f532ab11f 100644
--- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs
+++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs
@@ -182,7 +182,7 @@ namespace FlaxEditor.Windows.Assets
{
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/physics/colliders/collision-data.html")).LinkTooltip("See documentation to learn more");
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
diff --git a/Source/Editor/Windows/Assets/CubeTextureWindow.cs b/Source/Editor/Windows/Assets/CubeTextureWindow.cs
index 641441de7..7850f8960 100644
--- a/Source/Editor/Windows/Assets/CubeTextureWindow.cs
+++ b/Source/Editor/Windows/Assets/CubeTextureWindow.cs
@@ -140,9 +140,9 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_properties);
// Toolstrip
- _toolstrip.AddButton(Editor.Icons.Import32, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
+ _toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/textures/cube-textures.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/textures/cube-textures.html")).LinkTooltip("See documentation to learn more");
}
///
diff --git a/Source/Editor/Windows/Assets/FontWindow.cs b/Source/Editor/Windows/Assets/FontWindow.cs
index e33076606..63201ea9e 100644
--- a/Source/Editor/Windows/Assets/FontWindow.cs
+++ b/Source/Editor/Windows/Assets/FontWindow.cs
@@ -111,7 +111,7 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_proxy);
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
}
private void OnTextChanged()
diff --git a/Source/Editor/Windows/Assets/GameplayGlobalsWindow.cs b/Source/Editor/Windows/Assets/GameplayGlobalsWindow.cs
index f185e3eec..cca17e825 100644
--- a/Source/Editor/Windows/Assets/GameplayGlobalsWindow.cs
+++ b/Source/Editor/Windows/Assets/GameplayGlobalsWindow.cs
@@ -407,10 +407,10 @@ namespace FlaxEditor.Windows.Assets
_proxy = new PropertiesProxy();
_propertiesEditor.Select(_proxy);
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save asset");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save asset");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
_resetButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Rotate32, Reset).LinkTooltip("Resets the variables values to the default values");
diff --git a/Source/Editor/Windows/Assets/IESProfileWindow.cs b/Source/Editor/Windows/Assets/IESProfileWindow.cs
index 81ea9b496..c501a673d 100644
--- a/Source/Editor/Windows/Assets/IESProfileWindow.cs
+++ b/Source/Editor/Windows/Assets/IESProfileWindow.cs
@@ -27,9 +27,9 @@ namespace FlaxEditor.Windows.Assets
};
// Toolstrip
- _toolstrip.AddButton(editor.Icons.Import32, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
+ _toolstrip.AddButton(editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.PageScale32, _preview.CenterView).LinkTooltip("Center view");
+ _toolstrip.AddButton(editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");
}
///
diff --git a/Source/Editor/Windows/Assets/JsonAssetWindow.cs b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
index 779c8cc4e..c48125013 100644
--- a/Source/Editor/Windows/Assets/JsonAssetWindow.cs
+++ b/Source/Editor/Windows/Assets/JsonAssetWindow.cs
@@ -17,6 +17,9 @@ namespace FlaxEditor.Windows.Assets
{
private readonly CustomEditorPresenter _presenter;
private readonly ToolStripButton _saveButton;
+ private readonly ToolStripButton _undoButton;
+ private readonly ToolStripButton _redoButton;
+ private readonly Undo _undo;
private object _object;
private bool _isRegisteredForScriptsReload;
@@ -24,8 +27,16 @@ namespace FlaxEditor.Windows.Assets
public JsonAssetWindow(Editor editor, AssetItem item)
: base(editor, item)
{
+ // Undo
+ _undo = new Undo();
+ _undo.UndoDone += OnUndoRedo;
+ _undo.RedoDone += OnUndoRedo;
+
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
+ _toolstrip.AddSeparator();
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
// Panel
var panel = new Panel(ScrollBars.Vertical)
@@ -36,9 +47,19 @@ namespace FlaxEditor.Windows.Assets
};
// Properties
- _presenter = new CustomEditorPresenter(null, "Loading...");
+ _presenter = new CustomEditorPresenter(_undo, "Loading...");
_presenter.Panel.Parent = panel;
_presenter.Modified += MarkAsEdited;
+
+ // Setup input actions
+ InputActions.Add(options => options.Undo, _undo.PerformUndo);
+ InputActions.Add(options => options.Redo, _undo.PerformRedo);
+ }
+
+ private void OnUndoRedo(IUndoAction action)
+ {
+ MarkAsEdited();
+ UpdateToolstrip();
}
private void OnScriptsReloadBegin()
@@ -64,13 +85,14 @@ namespace FlaxEditor.Windows.Assets
}
ClearEditedFlag();
- _item.RefreshThumbnail();
}
///
protected override void UpdateToolstrip()
{
_saveButton.Enabled = IsEdited;
+ _undoButton.Enabled = _undo.CanUndo;
+ _redoButton.Enabled = _undo.CanRedo;
base.UpdateToolstrip();
}
@@ -80,6 +102,7 @@ namespace FlaxEditor.Windows.Assets
{
_object = Asset.CreateInstance();
_presenter.Select(_object);
+ _undo.Clear();
ClearEditedFlag();
// Auto-close on scripting reload if json asset is from game scripts (it might be reloaded)
diff --git a/Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs b/Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
new file mode 100644
index 000000000..633df8197
--- /dev/null
+++ b/Source/Editor/Windows/Assets/LocalizedStringTableWindow.cs
@@ -0,0 +1,212 @@
+// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+
+using System;
+using System.Collections.Generic;
+using FlaxEditor.Content;
+using FlaxEditor.CustomEditors;
+using FlaxEditor.GUI;
+using FlaxEngine;
+using FlaxEngine.GUI;
+using FlaxEngine.Utilities;
+
+namespace FlaxEditor.Windows.Assets
+{
+ ///
+ /// Editor window to view/modify asset.
+ ///
+ ///
+ ///
+ public sealed class LocalizedStringTableWindow : AssetEditorWindowBase
+ {
+ private readonly CustomEditorPresenter _presenter;
+ private readonly ToolStripButton _saveButton;
+ private readonly ToolStripButton _undoButton;
+ private readonly ToolStripButton _redoButton;
+ private readonly Undo _undo;
+ private Proxy _proxy;
+
+ private class EntryEditor : CustomEditor
+ {
+ private TextBox[] _textBoxes;
+ private bool _isRefreshing;
+
+ public override void Initialize(LayoutElementsContainer layout)
+ {
+ var values = (string[])Values[0];
+ if (values == null || values.Length == 0)
+ {
+ values = new string[1];
+ values[0] = string.Empty;
+ }
+ if (_textBoxes == null || _textBoxes.Length != values.Length)
+ _textBoxes = new TextBox[values.Length];
+ for (int i = 0; i < values.Length; i++)
+ {
+ var value = values[i];
+ var textBox = layout.TextBox(value.IsMultiline());
+ textBox.TextBox.Tag = i;
+ textBox.TextBox.Text = value;
+ textBox.TextBox.TextBoxEditEnd += OnEditEnd;
+ _textBoxes[i] = textBox.TextBox;
+ }
+ }
+
+ public override void Refresh()
+ {
+ base.Refresh();
+
+ var values = (string[])Values[0];
+ if (values != null && values.Length == _textBoxes.Length)
+ {
+ _isRefreshing = true;
+ var style = FlaxEngine.GUI.Style.Current;
+ var wrongColor = new Color(1.0f, 0.0f, 0.02745f, 1.0f);
+ var wrongColorBorder = Color.Lerp(wrongColor, style.TextBoxBackground, 0.6f);
+ for (int i = 0; i < _textBoxes.Length; i++)
+ {
+ var textBox = _textBoxes[i];
+ if (!textBox.IsEditing)
+ {
+ textBox.Text = values[i];
+ if (string.IsNullOrEmpty(textBox.Text))
+ {
+ textBox.BorderColor = wrongColorBorder;
+ textBox.BorderSelectedColor = wrongColor;
+ }
+ else
+ {
+ textBox.BorderColor = Color.Transparent;
+ textBox.BorderSelectedColor = style.BackgroundSelected;
+ }
+ }
+ }
+ _isRefreshing = false;
+ }
+ }
+
+ protected override void Deinitialize()
+ {
+ base.Deinitialize();
+
+ _textBoxes = null;
+ _isRefreshing = false;
+ }
+
+ private void OnEditEnd(TextBoxBase textBox)
+ {
+ if (_isRefreshing)
+ return;
+ var values = (string[])Values[0];
+ var length = Mathf.Max(values?.Length ?? 0, 1);
+ var toSet = new string[length];
+ if (values != null && values.Length == length)
+ Array.Copy(values, toSet, length);
+ var index = (int)textBox.Tag;
+ toSet[index] = textBox.Text;
+ SetValue(toSet);
+ }
+ }
+
+ private class Proxy
+ {
+ [EditorOrder(0), EditorDisplay("General"), Tooltip("The locale of the localized string table (eg. pl-PL)."),]
+ [CustomEditor(typeof(FlaxEditor.CustomEditors.Editors.CultureInfoEditor))]
+ public string Locale;
+
+ [EditorOrder(10), EditorDisplay("Entries", EditorDisplayAttribute.InlineStyle), Tooltip("The string table. Maps the message id into the localized text. For plural messages the list contains separate items for value numbers.")]
+ [Collection(Spacing = 10, OverrideEditorTypeName = "FlaxEditor.Windows.Assets.LocalizedStringTableWindow+EntryEditor")]
+ public Dictionary Entries;
+ }
+
+ ///
+ public LocalizedStringTableWindow(Editor editor, AssetItem item)
+ : base(editor, item)
+ {
+ // Undo
+ _undo = new Undo();
+ _undo.UndoDone += OnUndoRedo;
+ _undo.RedoDone += OnUndoRedo;
+
+ // Toolstrip
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
+ _toolstrip.AddSeparator();
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+
+ // Panel
+ var panel = new Panel(ScrollBars.Vertical)
+ {
+ AnchorPreset = AnchorPresets.StretchAll,
+ Offsets = new Margin(0, 0, _toolstrip.Bottom, 0),
+ Parent = this
+ };
+
+ // Properties
+ _presenter = new CustomEditorPresenter(_undo, "Loading...");
+ _presenter.Panel.Parent = panel;
+ _presenter.Modified += MarkAsEdited;
+
+ // Setup input actions
+ InputActions.Add(options => options.Undo, _undo.PerformUndo);
+ InputActions.Add(options => options.Redo, _undo.PerformRedo);
+ }
+
+ private void OnUndoRedo(IUndoAction action)
+ {
+ MarkAsEdited();
+ UpdateToolstrip();
+ }
+
+ ///
+ public override void Save()
+ {
+ if (!IsEdited)
+ return;
+
+ _asset.Locale = _proxy.Locale;
+ _asset.Entries = _proxy.Entries;
+ if (_asset.Save(_item.Path))
+ {
+ Editor.LogError("Cannot save asset.");
+ return;
+ }
+
+ ClearEditedFlag();
+ }
+
+ ///
+ protected override void UpdateToolstrip()
+ {
+ _saveButton.Enabled = IsEdited;
+ _undoButton.Enabled = _undo.CanUndo;
+ _redoButton.Enabled = _undo.CanRedo;
+
+ base.UpdateToolstrip();
+ }
+
+ ///
+ protected override void OnAssetLoaded()
+ {
+ _proxy = new Proxy
+ {
+ Locale = _asset.Locale,
+ Entries = _asset.Entries,
+ };
+ _presenter.Select(_proxy);
+ _undo.Clear();
+ ClearEditedFlag();
+
+ base.OnAssetLoaded();
+ }
+
+ ///
+ public override void OnItemReimported(ContentItem item)
+ {
+ // Refresh the properties (will get new data in OnAssetLoaded)
+ _presenter.Deselect();
+ ClearEditedFlag();
+
+ base.OnItemReimported(item);
+ }
+ }
+}
diff --git a/Source/Editor/Windows/Assets/MaterialFunctionWindow.cs b/Source/Editor/Windows/Assets/MaterialFunctionWindow.cs
index 20b091a04..6b62d1689 100644
--- a/Source/Editor/Windows/Assets/MaterialFunctionWindow.cs
+++ b/Source/Editor/Windows/Assets/MaterialFunctionWindow.cs
@@ -29,7 +29,7 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
}
///
diff --git a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
index 4f67e4f72..c5becfe7d 100644
--- a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
+++ b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs
@@ -327,14 +327,14 @@ namespace FlaxEditor.Windows.Assets
_undo.ActionDone += OnAction;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(Editor.Icons.Rotate32, OnRevertAllParameters).LinkTooltip("Revert all the parameters to the default values");
+ _toolstrip.AddButton(Editor.Icons.Rotate64, OnRevertAllParameters).LinkTooltip("Revert all the parameters to the default values");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/instanced-materials/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/instanced-materials/index.html")).LinkTooltip("See documentation to learn more");
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
diff --git a/Source/Editor/Windows/Assets/MaterialWindow.cs b/Source/Editor/Windows/Assets/MaterialWindow.cs
index 3e0ac8fb1..37dcc40ce 100644
--- a/Source/Editor/Windows/Assets/MaterialWindow.cs
+++ b/Source/Editor/Windows/Assets/MaterialWindow.cs
@@ -233,8 +233,8 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.BracketsSlash32, ShowSourceCode).LinkTooltip("Show generated shader source code");
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode).LinkTooltip("Show generated shader source code");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/materials/index.html")).LinkTooltip("See documentation to learn more");
}
private void ShowSourceCode()
diff --git a/Source/Editor/Windows/Assets/ModelBaseWindow.cs b/Source/Editor/Windows/Assets/ModelBaseWindow.cs
index 74b690f98..7382d727c 100644
--- a/Source/Editor/Windows/Assets/ModelBaseWindow.cs
+++ b/Source/Editor/Windows/Assets/ModelBaseWindow.cs
@@ -102,7 +102,7 @@ namespace FlaxEditor.Windows.Assets
: base(editor, item)
{
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.None)
diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs
index b16a01a73..90b02cbb6 100644
--- a/Source/Editor/Windows/Assets/ModelWindow.cs
+++ b/Source/Editor/Windows/Assets/ModelWindow.cs
@@ -565,7 +565,6 @@ namespace FlaxEditor.Windows.Assets
public UVsLayoutPreviewControl()
{
Offsets = new Margin(4);
- AnchorPreset = AnchorPresets.HorizontalStretchMiddle;
AutomaticInvalidate = false;
}
@@ -619,9 +618,9 @@ namespace FlaxEditor.Windows.Assets
}
///
- protected override void DrawChildren()
+ public override void DrawSelf()
{
- base.DrawChildren();
+ base.DrawSelf();
var size = Size;
if (_channel == UVChannel.None || size.MaxValue < 5.0f)
@@ -825,7 +824,7 @@ namespace FlaxEditor.Windows.Assets
{
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/models/index.html")).LinkTooltip("See documentation to learn more");
// Model preview
_preview = new Preview(this)
diff --git a/Source/Editor/Windows/Assets/ParticleEmitterFunctionWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterFunctionWindow.cs
index a449aec82..abad899f4 100644
--- a/Source/Editor/Windows/Assets/ParticleEmitterFunctionWindow.cs
+++ b/Source/Editor/Windows/Assets/ParticleEmitterFunctionWindow.cs
@@ -29,7 +29,7 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
}
///
diff --git a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs
index 21107452f..1968c5735 100644
--- a/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs
+++ b/Source/Editor/Windows/Assets/ParticleEmitterWindow.cs
@@ -139,8 +139,8 @@ namespace FlaxEditor.Windows.Assets
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.BracketsSlash32, ShowSourceCode).LinkTooltip("Show generated shader source code");
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode).LinkTooltip("Show generated shader source code");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
}
private void ShowSourceCode()
diff --git a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
index b601f3786..acc3c658a 100644
--- a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
+++ b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs
@@ -356,12 +356,12 @@ namespace FlaxEditor.Windows.Assets
propertiesEditor.Select(new GeneralProxy(this));
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more");
// Setup input actions
InputActions.Add(options => options.Undo, _undo.PerformUndo);
diff --git a/Source/Editor/Windows/Assets/PrefabWindow.cs b/Source/Editor/Windows/Assets/PrefabWindow.cs
index 8dd4a6ebe..bec9bf7fe 100644
--- a/Source/Editor/Windows/Assets/PrefabWindow.cs
+++ b/Source/Editor/Windows/Assets/PrefabWindow.cs
@@ -154,16 +154,16 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Modified += MarkAsEdited;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _toolStripUndo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _toolStripRedo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _toolStripUndo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _toolStripRedo = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
_toolStripTranslate = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Translate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate).LinkTooltip("Change Gizmo tool mode to Translate (1)");
_toolStripRotate = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Rotate32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate).LinkTooltip("Change Gizmo tool mode to Rotate (2)");
_toolStripScale = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Scale32, () => _viewport.TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale).LinkTooltip("Change Gizmo tool mode to Scale (3)");
_toolstrip.AddSeparator();
- _toolStripLiveReload = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Reload32, () => LiveReload = !LiveReload).SetChecked(true).SetAutoCheck(true).LinkTooltip("Live changes preview (applies prefab changes on modification by auto)");
+ _toolStripLiveReload = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Refresh64, () => LiveReload = !LiveReload).SetChecked(true).SetAutoCheck(true).LinkTooltip("Live changes preview (applies prefab changes on modification by auto)");
Editor.Prefabs.PrefabApplied += OnPrefabApplied;
ScriptsBuilder.ScriptsReloadBegin += OnScriptsReloadBegin;
diff --git a/Source/Editor/Windows/Assets/PreviewsCacheWindow.cs b/Source/Editor/Windows/Assets/PreviewsCacheWindow.cs
index d1fe73976..a857246da 100644
--- a/Source/Editor/Windows/Assets/PreviewsCacheWindow.cs
+++ b/Source/Editor/Windows/Assets/PreviewsCacheWindow.cs
@@ -28,7 +28,7 @@ namespace FlaxEditor.Windows.Assets
};
// Toolstrip
- _toolstrip.AddButton(editor.Icons.PageScale32, _preview.CenterView).LinkTooltip("Center view");
+ _toolstrip.AddButton(editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");
}
///
diff --git a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
index c162eac3a..821b5ccc5 100644
--- a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
+++ b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs
@@ -634,14 +634,14 @@ namespace FlaxEditor.Windows.Assets
_timeline.PlayerChanged += OnTimelinePlayerChanged;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _renderButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Build32, OnRenderButtonClicked).LinkTooltip("Open the scene animation rendering utility...");
+ _renderButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Build64, OnRenderButtonClicked).LinkTooltip("Open the scene animation rendering utility...");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/scene-animations/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/scene-animations/index.html")).LinkTooltip("See documentation to learn more");
// Preview player picker
var previewPlayerPickerContainer = new ContainerControl();
diff --git a/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs b/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs
index 86066f293..d65a564b2 100644
--- a/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs
+++ b/Source/Editor/Windows/Assets/SkeletonMaskWindow.cs
@@ -182,9 +182,9 @@ namespace FlaxEditor.Windows.Assets
: base(editor, item)
{
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save asset to the file");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save asset to the file");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skeleton-mask.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skeleton-mask.html")).LinkTooltip("See documentation to learn more");
// Split Panel
_split = new SplitPanel(Orientation.Horizontal, ScrollBars.None, ScrollBars.Vertical)
diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
index f3d228f45..9123b8d9a 100644
--- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
+++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs
@@ -114,9 +114,9 @@ namespace FlaxEditor.Windows.Assets
}
///
- public override void Draw()
+ public override void DrawSelf()
{
- base.Draw();
+ base.DrawSelf();
var style = Style.Current;
var asset = _window.Asset;
@@ -676,7 +676,6 @@ namespace FlaxEditor.Windows.Assets
public UVsLayoutPreviewControl()
{
Offsets = new Margin(4);
- AnchorPreset = AnchorPresets.HorizontalStretchMiddle;
AutomaticInvalidate = false;
}
@@ -920,9 +919,9 @@ namespace FlaxEditor.Windows.Assets
{
// Toolstrip
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Bone32, () => _preview.ShowNodes = !_preview.ShowNodes).SetAutoCheck(true).LinkTooltip("Show animated model nodes debug view");
+ _toolstrip.AddButton(editor.Icons.Bone64, () => _preview.ShowNodes = !_preview.ShowNodes).SetAutoCheck(true).LinkTooltip("Show animated model nodes debug view");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/animation/skinned-model/index.html")).LinkTooltip("See documentation to learn more");
// Model preview
_preview = new Preview(this)
diff --git a/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs b/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs
index e82c1dd12..232f69165 100644
--- a/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs
+++ b/Source/Editor/Windows/Assets/SpriteAtlasWindow.cs
@@ -1,11 +1,13 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+using System.Linq;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.Content.Import;
using FlaxEditor.CustomEditors;
using FlaxEditor.CustomEditors.Editors;
using FlaxEditor.GUI;
+using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Previews;
using FlaxEngine;
@@ -99,18 +101,16 @@ namespace FlaxEditor.Windows.Assets
}
[EditorOrder(0), EditorDisplay("Sprites")]
- [CustomEditor(typeof(SpritesColelctionEditor))]
+ [CustomEditor(typeof(SpritesCollectionEditor))]
public SpriteEntry[] Sprites;
[EditorOrder(1000), EditorDisplay("Import Settings", EditorDisplayAttribute.InlineStyle)]
- public TextureImportSettings ImportSettings { get; set; } = new TextureImportSettings();
+ public TextureImportSettings ImportSettings = new TextureImportSettings();
public sealed class ProxyEditor : GenericEditor
{
public override void Initialize(LayoutElementsContainer layout)
{
- var window = ((PropertiesProxy)Values[0])._window;
-
base.Initialize(layout);
layout.Space(10);
@@ -119,24 +119,46 @@ namespace FlaxEditor.Windows.Assets
}
}
- public sealed class SpritesColelctionEditor : CustomEditor
+ public sealed class SpritesCollectionEditor : CustomEditor
{
public override DisplayStyle Style => DisplayStyle.InlineIntoParent;
public override void Initialize(LayoutElementsContainer layout)
{
var sprites = (SpriteEntry[])Values[0];
-
if (sprites != null)
{
var elementType = new ScriptType(typeof(SpriteEntry));
for (int i = 0; i < sprites.Length; i++)
{
var group = layout.Group(sprites[i].Name);
+ group.Panel.Tag = i;
+ group.Panel.MouseButtonRightClicked += OnGroupPanelMouseButtonRightClicked;
group.Object(new ListValueContainer(elementType, i, Values));
}
}
}
+
+ private void OnGroupPanelMouseButtonRightClicked(DropPanel groupPanel, Vector2 location)
+ {
+ var menu = new ContextMenu();
+
+ var deleteSprite = menu.AddButton("Delete sprite");
+ deleteSprite.Tag = groupPanel.Tag;
+ deleteSprite.ButtonClicked += OnDeleteSpriteClicked;
+
+ menu.Show(groupPanel, location);
+ }
+
+ private void OnDeleteSpriteClicked(ContextMenuButton button)
+ {
+ var window = ((PropertiesProxy)ParentEditor.Values[0])._window;
+ var index = (int)button.Tag;
+ window.Asset.RemoveSprite(index);
+ window.MarkAsEdited();
+ window._properties.UpdateSprites();
+ window._propertiesEditor.BuildLayout();
+ }
}
///
@@ -185,6 +207,7 @@ namespace FlaxEditor.Windows.Assets
///
public void Reimport()
{
+ ImportSettings.Sprites = null; // Don't override sprites (use sprites from asset)
Editor.Instance.ContentImporting.Reimport((BinaryAssetItem)_window.Item, ImportSettings, true);
}
@@ -241,14 +264,14 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Modified += MarkAsEdited;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save32, Save).LinkTooltip("Save");
- _toolstrip.AddButton(editor.Icons.Import32, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(editor.Icons.Save64, Save).LinkTooltip("Save");
+ _toolstrip.AddButton(editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.AddDoc32, () =>
+ _toolstrip.AddButton(editor.Icons.AddFile64, () =>
{
var sprite = new Sprite
{
- Name = "New Sprite",
+ Name = StringUtils.IncrementNameNumber("New Sprite", name => Asset.Sprites.All(s => s.Name != name)),
Area = new Rectangle(Vector2.Zero, Vector2.One),
};
Asset.AddSprite(sprite);
@@ -257,7 +280,7 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.BuildLayout();
}).LinkTooltip("Add a new sprite");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.PageScale32, _preview.CenterView).LinkTooltip("Center view");
+ _toolstrip.AddButton(editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");
}
///
diff --git a/Source/Editor/Windows/Assets/TextureWindow.cs b/Source/Editor/Windows/Assets/TextureWindow.cs
index 9f6698528..481c48f47 100644
--- a/Source/Editor/Windows/Assets/TextureWindow.cs
+++ b/Source/Editor/Windows/Assets/TextureWindow.cs
@@ -140,11 +140,11 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_properties);
// Toolstrip
- _toolstrip.AddButton(Editor.Icons.Import32, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
+ _toolstrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.Reimport((BinaryAssetItem)Item)).LinkTooltip("Reimport");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(Editor.Icons.PageScale32, _preview.CenterView).LinkTooltip("Center view");
+ _toolstrip.AddButton(Editor.Icons.CenterView64, _preview.CenterView).LinkTooltip("Center view");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/textures/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/graphics/textures/index.html")).LinkTooltip("See documentation to learn more");
}
///
diff --git a/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs b/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
index 57041169a..fe87299e2 100644
--- a/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
+++ b/Source/Editor/Windows/Assets/VisjectFunctionSurfaceWindow.cs
@@ -68,12 +68,12 @@ namespace FlaxEditor.Windows.Assets
_undo.ActionDone += OnUndoRedo;
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.PageScale32, ShowWholeGraph).LinkTooltip("Show whole graph");
+ _toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
// Panel
_panel = new Panel(ScrollBars.None)
diff --git a/Source/Editor/Windows/Assets/VisualScriptWindow.cs b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
index 8207740f1..b9ddafa87 100644
--- a/Source/Editor/Windows/Assets/VisualScriptWindow.cs
+++ b/Source/Editor/Windows/Assets/VisualScriptWindow.cs
@@ -212,7 +212,7 @@ namespace FlaxEditor.Windows.Assets
IsScrollable = false,
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(Editor.Instance.Icons.Add48),
+ Brush = new SpriteBrush(Editor.Instance.Icons.Add64),
};
addNewFunction.Clicked += OnAddNewFunctionClicked;
@@ -227,7 +227,7 @@ namespace FlaxEditor.Windows.Assets
IsScrollable = false,
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
Margin = new Margin(1),
- Brush = new SpriteBrush(Editor.Instance.Icons.Import32),
+ Brush = new SpriteBrush(Editor.Instance.Icons.Import64),
};
overrideMethod.Clicked += OnOverrideMethodClicked;
}
@@ -385,23 +385,23 @@ namespace FlaxEditor.Windows.Assets
_propertiesEditor.Select(_properties);
// Toolstrip
- _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save32, Save).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Save64, Save).LinkTooltip("Save");
_toolstrip.AddSeparator();
- _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo32, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
- _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo32, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
+ _undoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Undo64, _undo.PerformUndo).LinkTooltip("Undo (Ctrl+Z)");
+ _redoButton = (ToolStripButton)_toolstrip.AddButton(Editor.Icons.Redo64, _undo.PerformRedo).LinkTooltip("Redo (Ctrl+Y)");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.PageScale32, ShowWholeGraph).LinkTooltip("Show whole graph");
+ _toolstrip.AddButton(editor.Icons.CenterView64, ShowWholeGraph).LinkTooltip("Show whole graph");
_toolstrip.AddSeparator();
- _toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/scripting/visual/index.html")).LinkTooltip("See documentation to learn more");
+ _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/scripting/visual/index.html")).LinkTooltip("See documentation to learn more");
_debugToolstripControls = new[]
{
_toolstrip.AddSeparator(),
- _toolstrip.AddButton(editor.Icons.Play32, OnDebuggerContinue).LinkTooltip("Continue (F5)"),
- _toolstrip.AddButton(editor.Icons.Find32, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
- _toolstrip.AddButton(editor.Icons.ArrowRight32, OnDebuggerStepOver).LinkTooltip("Step Over (F10)"),
- _toolstrip.AddButton(editor.Icons.ArrowDown32, OnDebuggerStepInto).LinkTooltip("Step Into (F11)"),
- _toolstrip.AddButton(editor.Icons.ArrowUp32, OnDebuggerStepOut).LinkTooltip("Step Out (Shift+F11)"),
- _toolstrip.AddButton(editor.Icons.Stop32, OnDebuggerStop).LinkTooltip("Stop debugging"),
+ _toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip("Continue (F5)"),
+ _toolstrip.AddButton(editor.Icons.Search64, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
+ _toolstrip.AddButton(editor.Icons.Right64, OnDebuggerStepOver).LinkTooltip("Step Over (F10)"),
+ _toolstrip.AddButton(editor.Icons.Down64, OnDebuggerStepInto).LinkTooltip("Step Into (F11)"),
+ _toolstrip.AddButton(editor.Icons.Up64, OnDebuggerStepOut).LinkTooltip("Step Out (Shift+F11)"),
+ _toolstrip.AddButton(editor.Icons.Stop64, OnDebuggerStop).LinkTooltip("Stop debugging"),
};
foreach (var control in _debugToolstripControls)
control.Visible = false;
diff --git a/Source/Editor/Windows/ContentWindow.cs b/Source/Editor/Windows/ContentWindow.cs
index cd92bc300..88a976d2b 100644
--- a/Source/Editor/Windows/ContentWindow.cs
+++ b/Source/Editor/Windows/ContentWindow.cs
@@ -77,11 +77,11 @@ namespace FlaxEditor.Windows
{
Parent = this,
};
- _importButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Import32, () => Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder)).LinkTooltip("Import content");
+ _importButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Import64, () => Editor.ContentImporting.ShowImportFileDialog(CurrentViewFolder)).LinkTooltip("Import content");
_toolStrip.AddSeparator();
- _navigateBackwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.ArrowLeft32, NavigateBackward).LinkTooltip("Navigate backward");
- _navigateForwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.ArrowRight32, NavigateForward).LinkTooltip("Navigate forward");
- _navigateUpButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.ArrowUp32, NavigateUp).LinkTooltip("Navigate up");
+ _navigateBackwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Left64, NavigateBackward).LinkTooltip("Navigate backward");
+ _navigateForwardButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Right64, NavigateForward).LinkTooltip("Navigate forward");
+ _navigateUpButton = (ToolStripButton)_toolStrip.AddButton(Editor.Icons.Up64, NavigateUp).LinkTooltip("Navigate up");
// Navigation bar
_navigationBar = new NavigationBar
diff --git a/Source/Editor/Windows/DebugLogWindow.cs b/Source/Editor/Windows/DebugLogWindow.cs
index 7ffe5c923..bc80a0ba7 100644
--- a/Source/Editor/Windows/DebugLogWindow.cs
+++ b/Source/Editor/Windows/DebugLogWindow.cs
@@ -312,9 +312,9 @@ namespace FlaxEditor.Windows
_clearOnPlayButton = (ToolStripButton)toolstrip.AddButton("Clear on Play").SetAutoCheck(true).SetChecked(true).LinkTooltip("Clears all log entries on enter playmode");
_pauseOnErrorButton = (ToolStripButton)toolstrip.AddButton("Pause on Error").SetAutoCheck(true).LinkTooltip("Performs auto pause on error");
toolstrip.AddSeparator();
- _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error32, () => UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides error messages");
- _groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () => UpdateLogTypeVisibility(LogGroup.Warning, _groupButtons[1].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides warning messages");
- _groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () => UpdateLogTypeVisibility(LogGroup.Info, _groupButtons[2].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides info messages");
+ _groupButtons[0] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Error64, () => UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides error messages");
+ _groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning64, () => UpdateLogTypeVisibility(LogGroup.Warning, _groupButtons[1].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides warning messages");
+ _groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info64, () => UpdateLogTypeVisibility(LogGroup.Info, _groupButtons[2].Checked)).SetAutoCheck(true).SetChecked(true).LinkTooltip("Shows/hides info messages");
UpdateCount();
// Split panel
@@ -348,9 +348,9 @@ namespace FlaxEditor.Windows
};
// Cache entries icons
- IconInfo = Editor.Icons.Info32;
- IconWarning = Editor.Icons.Warning32;
- IconError = Editor.Icons.Error32;
+ IconInfo = Editor.Icons.Info64;
+ IconWarning = Editor.Icons.Warning64;
+ IconError = Editor.Icons.Error64;
// Bind events
Editor.Options.OptionsChanged += OnEditorOptionsChanged;
diff --git a/Source/Editor/Windows/EditorOptionsWindow.cs b/Source/Editor/Windows/EditorOptionsWindow.cs
index 01b26a65c..2e700686e 100644
--- a/Source/Editor/Windows/EditorOptionsWindow.cs
+++ b/Source/Editor/Windows/EditorOptionsWindow.cs
@@ -38,7 +38,7 @@ namespace FlaxEditor.Windows
{
Parent = this
};
- _saveButton = (ToolStripButton)toolstrip.AddButton(editor.Icons.Save32, SaveData).LinkTooltip("Save");
+ _saveButton = (ToolStripButton)toolstrip.AddButton(editor.Icons.Save64, SaveData).LinkTooltip("Save");
_saveButton.Enabled = false;
_tabs = new Tabs
diff --git a/Source/Editor/Windows/GameWindow.cs b/Source/Editor/Windows/GameWindow.cs
index 5478cfbef..26cef2621 100644
--- a/Source/Editor/Windows/GameWindow.cs
+++ b/Source/Editor/Windows/GameWindow.cs
@@ -1,11 +1,11 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
+using System;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Options;
using FlaxEngine;
using FlaxEngine.GUI;
-using FlaxEngine.Utilities;
namespace FlaxEditor.Windows
{
@@ -18,6 +18,7 @@ namespace FlaxEditor.Windows
private readonly RenderOutputControl _viewport;
private readonly GameRoot _guiRoot;
private bool _showGUI = true;
+ private bool _showDebugDraw = false;
private float _gameStartTime;
///
@@ -36,14 +37,20 @@ namespace FlaxEditor.Windows
if (value != _showGUI)
{
_showGUI = value;
-
- // Update root if it's in game
- if (Editor.StateMachine.IsPlayMode)
- _guiRoot.Visible = value;
+ _guiRoot.Visible = value;
}
}
}
+ ///
+ /// Gets or sets a value indicating whether show Debug Draw shapes in the view or keep it hidden.
+ ///
+ public bool ShowDebugDraw
+ {
+ get => _showDebugDraw;
+ set => _showDebugDraw = value;
+ }
+
///
/// Gets or sets a value indicating whether center mouse position on window focus in play mode. Helps when working with games that lock mouse cursor.
///
@@ -191,6 +198,7 @@ namespace FlaxEditor.Windows
AutoFocus = false,
Parent = this
};
+ task.PostRender += OnPostRender;
// Override the game GUI root
_guiRoot = new GameRoot
@@ -214,6 +222,31 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.StepFrame, Editor.Simulation.RequestPlayOneFrame);
}
+ private void OnPostRender(GPUContext context, RenderContext renderContext)
+ {
+ // Debug Draw shapes
+ if (_showDebugDraw)
+ {
+ var task = _viewport.Task;
+
+ // Draw actors debug shapes manually if editor viewport is hidden (game viewport task is always rendered before editor viewports)
+ var editWindowViewport = Editor.Windows.EditWin.Viewport;
+ if (editWindowViewport.Task.LastUsedFrame != Engine.FrameCount)
+ {
+ unsafe
+ {
+ var drawDebugData = editWindowViewport.DebugDrawData;
+ fixed (IntPtr* actors = drawDebugData.ActorsPtrs)
+ {
+ DebugDraw.DrawActors(new IntPtr(actors), drawDebugData.ActorsCount, true);
+ }
+ }
+ }
+
+ DebugDraw.Draw(ref renderContext, task.OutputView);
+ }
+ }
+
private void OnOptionsChanged(EditorOptions options)
{
CenterMouseOnFocus = options.Interface.CenterMouseOnGameWinFocus;
@@ -278,6 +311,22 @@ namespace FlaxEditor.Windows
takeScreenshot.Clicked += TakeScreenshot;
}
+ menu.AddSeparator();
+
+ // Show GUI
+ {
+ var button = menu.AddButton("Show GUI");
+ var checkbox = new CheckBox(140, 2, ShowGUI) { Parent = button };
+ checkbox.StateChanged += x => ShowGUI = x.Checked;
+ }
+
+ // Show Debug Draw
+ {
+ var button = menu.AddButton("Show Debug Draw");
+ var checkbox = new CheckBox(140, 2, ShowDebugDraw) { Parent = button };
+ checkbox.StateChanged += x => ShowDebugDraw = x.Checked;
+ }
+
menu.MinimumWidth = 200;
menu.AddSeparator();
}
@@ -408,7 +457,7 @@ namespace FlaxEditor.Windows
base.OnStartContainsFocus();
// Center mouse in play mode
- if (CenterMouseOnFocus && Editor.StateMachine.IsPlayMode)
+ if (CenterMouseOnFocus && Editor.StateMachine.IsPlayMode && !Editor.StateMachine.PlayingState.IsPaused)
{
Vector2 center = PointToWindow(Size * 0.5f);
Root.MousePosition = center;
diff --git a/Source/Editor/Windows/PluginsWindow.cs b/Source/Editor/Windows/PluginsWindow.cs
index 28b6c20a5..a14a38774 100644
--- a/Source/Editor/Windows/PluginsWindow.cs
+++ b/Source/Editor/Windows/PluginsWindow.cs
@@ -53,7 +53,7 @@ namespace FlaxEditor.Windows
var iconImage = new Image
{
- Brush = new SpriteBrush(Editor.Instance.Icons.Plugin64),
+ Brush = new SpriteBrush(Editor.Instance.Icons.Plugin128),
Parent = this,
Bounds = new Rectangle(margin, margin, iconSize, iconSize),
};
diff --git a/Source/Editor/Windows/Profiler/CPU.cs b/Source/Editor/Windows/Profiler/CPU.cs
index 9e79832ab..d33325fa3 100644
--- a/Source/Editor/Windows/Profiler/CPU.cs
+++ b/Source/Editor/Windows/Profiler/CPU.cs
@@ -5,6 +5,29 @@ using FlaxEditor.GUI;
using FlaxEngine;
using FlaxEngine.GUI;
+namespace FlaxEngine
+{
+ partial class ProfilerCPU
+ {
+ partial struct Event
+ {
+ ///
+ /// Gets the event name.
+ ///
+ public unsafe string Name
+ {
+ get
+ {
+ fixed (char* name = &Name0)
+ {
+ return new string(name);
+ }
+ }
+ }
+ }
+ }
+}
+
namespace FlaxEditor.Windows.Profiler
{
///
@@ -204,7 +227,7 @@ namespace FlaxEditor.Windows.Profiler
{
var e = events[i];
- if (e.Depth == 0 && new string(e.Name) == "Update")
+ if (e.Depth == 0 && e.Name == "Update")
{
return new ViewRange(ref e);
}
@@ -225,7 +248,7 @@ namespace FlaxEditor.Windows.Profiler
double scale = 100.0;
float x = (float)((e.Start - startTime) * scale);
float width = (float)(length * scale);
- string name = new string(e.Name).Replace("::", ".");
+ string name = e.Name.Replace("::", ".");
var control = new Timeline.Event(x + xOffset, e.Depth + depthOffset, width)
{
@@ -399,7 +422,7 @@ namespace FlaxEditor.Windows.Profiler
subEventsMemoryTotal += sub.ManagedMemoryAllocation + e.NativeMemoryAllocation;
}
- string name = new string(e.Name).Replace("::", ".");
+ string name = e.Name.Replace("::", ".");
var row = new Row
{
diff --git a/Source/Editor/Windows/Profiler/ProfilerWindow.cs b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
index e6de1fd69..27a718077 100644
--- a/Source/Editor/Windows/Profiler/ProfilerWindow.cs
+++ b/Source/Editor/Windows/Profiler/ProfilerWindow.cs
@@ -92,20 +92,20 @@ namespace FlaxEditor.Windows.Profiler
{
Parent = this,
};
- _liveRecordingButton = toolstrip.AddButton(editor.Icons.Play32);
+ _liveRecordingButton = toolstrip.AddButton(editor.Icons.Play64);
_liveRecordingButton.LinkTooltip("Live profiling events recording");
_liveRecordingButton.AutoCheck = true;
_clearButton = toolstrip.AddButton(editor.Icons.Rotate32, Clear);
_clearButton.LinkTooltip("Clear data");
toolstrip.AddSeparator();
- _prevFrameButton = toolstrip.AddButton(editor.Icons.ArrowLeft32, () => ViewFrameIndex--);
+ _prevFrameButton = toolstrip.AddButton(editor.Icons.Left64, () => ViewFrameIndex--);
_prevFrameButton.LinkTooltip("Previous frame");
- _nextFrameButton = toolstrip.AddButton(editor.Icons.ArrowRight32, () => ViewFrameIndex++);
+ _nextFrameButton = toolstrip.AddButton(editor.Icons.Right64, () => ViewFrameIndex++);
_nextFrameButton.LinkTooltip("Next frame");
- _lastFrameButton = toolstrip.AddButton(editor.Icons.Step32, () => ViewFrameIndex = -1);
+ _lastFrameButton = toolstrip.AddButton(editor.Icons.Skip64, () => ViewFrameIndex = -1);
_lastFrameButton.LinkTooltip("Current frame");
toolstrip.AddSeparator();
- _showOnlyLastUpdateEventsButton = toolstrip.AddButton(editor.Icons.PageScale32, () => ShowOnlyLastUpdateEvents = !ShowOnlyLastUpdateEvents);
+ _showOnlyLastUpdateEventsButton = toolstrip.AddButton(editor.Icons.CenterView64, () => ShowOnlyLastUpdateEvents = !ShowOnlyLastUpdateEvents);
_showOnlyLastUpdateEventsButton.LinkTooltip("Show only last update events and hide events from the other callbacks (e.g. draw or fixed update)");
_tabs = new Tabs
diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp
index 2d2d26ead..4a107e467 100644
--- a/Source/Editor/Windows/SplashScreen.cpp
+++ b/Source/Editor/Windows/SplashScreen.cpp
@@ -2,7 +2,9 @@
#include "SplashScreen.h"
#include "Engine/Core/Log.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Engine/CommandLine.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Render2D/FontAsset.h"
#include "Engine/Render2D/Font.h"
#include "Engine/Render2D/TextLayoutOptions.h"
@@ -115,11 +117,21 @@ const Char* SplashScreenQuotes[] =
TEXT("Cyberpunk of game engines"),
TEXT("That's what she said"),
TEXT("Compiling Shaders (93,788)"),
- TEXT("Hi There"),
+ TEXT("Hello There"),
TEXT("BAGUETTE"),
TEXT("All we had to do was follow the damn train, CJ"),
TEXT("28 stab wounds"),
TEXT("Here we go again"),
+ TEXT("@everyone"),
+ TEXT("Potato"),
+ TEXT("Python is a programming snek"),
+ TEXT("Flax will start when pigs will fly"),
+ TEXT("I'm the android sent by CyberLife"),
+ TEXT("Fancy-ass ray tracing, rtx on, lighting"),
+ TEXT("ZOINKS"),
+ TEXT("Scooby dooby doo"),
+ TEXT("You shall not load!"),
+ TEXT("The roof, the roof, the roof is on fire!")
};
SplashScreen::~SplashScreen()
diff --git a/Source/Editor/Windows/ToolboxWindow.cs b/Source/Editor/Windows/ToolboxWindow.cs
index 7084addd1..33827ea93 100644
--- a/Source/Editor/Windows/ToolboxWindow.cs
+++ b/Source/Editor/Windows/ToolboxWindow.cs
@@ -319,10 +319,10 @@ namespace FlaxEditor.Windows
Parent = this
};
- TabsControl.AddTab(Spawn = new SpawnTab(Editor.Icons.Add48, Editor));
- TabsControl.AddTab(VertexPaint = new VertexPaintingTab(Editor.Icons.Paint48, Editor));
- TabsControl.AddTab(Foliage = new FoliageTab(Editor.Icons.Foliage48, Editor));
- TabsControl.AddTab(Carve = new CarveTab(Editor.Icons.Mountain48, Editor));
+ TabsControl.AddTab(Spawn = new SpawnTab(Editor.Icons.Toolbox96, Editor));
+ TabsControl.AddTab(VertexPaint = new VertexPaintingTab(Editor.Icons.Paint96, Editor));
+ TabsControl.AddTab(Foliage = new FoliageTab(Editor.Icons.Foliage96, Editor));
+ TabsControl.AddTab(Carve = new CarveTab(Editor.Icons.Terrain96, Editor));
TabsControl.SelectedTabIndex = 0;
}
diff --git a/Source/Editor/Windows/VisualScriptDebuggerWindow.cs b/Source/Editor/Windows/VisualScriptDebuggerWindow.cs
index b9f20ff2f..f91d0cea9 100644
--- a/Source/Editor/Windows/VisualScriptDebuggerWindow.cs
+++ b/Source/Editor/Windows/VisualScriptDebuggerWindow.cs
@@ -404,13 +404,13 @@ namespace FlaxEditor.Windows
{
Parent = this
};
- toolstrip.AddButton(editor.Icons.Docs32, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/scripting/visual/index.html")).LinkTooltip("See documentation to learn more");
+ toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/scripting/visual/index.html")).LinkTooltip("See documentation to learn more");
_debugToolstripControls = new[]
{
toolstrip.AddSeparator(),
- toolstrip.AddButton(editor.Icons.Play32, OnDebuggerContinue).LinkTooltip("Continue (F5)"),
- toolstrip.AddButton(editor.Icons.Find32, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
- toolstrip.AddButton(editor.Icons.Stop32, OnDebuggerStop).LinkTooltip("Stop debugging"),
+ toolstrip.AddButton(editor.Icons.Play64, OnDebuggerContinue).LinkTooltip("Continue (F5)"),
+ toolstrip.AddButton(editor.Icons.Search64, OnDebuggerNavigateToCurrentNode).LinkTooltip("Navigate to the current stack trace node"),
+ toolstrip.AddButton(editor.Icons.Stop64, OnDebuggerStop).LinkTooltip("Stop debugging"),
};
foreach (var control in _debugToolstripControls)
control.Visible = Editor.Simulation.IsDuringBreakpointHang;
diff --git a/Source/Engine/Animations/AnimationData.h b/Source/Engine/Animations/AnimationData.h
index 139c06aa9..6a782d8d6 100644
--- a/Source/Engine/Animations/AnimationData.h
+++ b/Source/Engine/Animations/AnimationData.h
@@ -2,7 +2,8 @@
#pragma once
-#include "Curve.h"
+#include "Engine/Core/Types/String.h"
+#include "Engine/Animations/Curve.h"
#include "Engine/Core/Math/Transform.h"
///
diff --git a/Source/Engine/Animations/AnimationManager.cpp b/Source/Engine/Animations/AnimationManager.cpp
index c64a61856..6614c611a 100644
--- a/Source/Engine/Animations/AnimationManager.cpp
+++ b/Source/Engine/Animations/AnimationManager.cpp
@@ -6,7 +6,8 @@
#include "Engine/Engine/Time.h"
#include "Engine/Engine/EngineService.h"
-Array UpdateList(256);
+Array UpdateList;
+Array UpdateBones;
class AnimationManagerService : public EngineService
{
@@ -67,10 +68,11 @@ void AnimationManagerService::Update()
}
animatedModel->GraphInstance.LastUpdateTime = t;
- const auto bones = graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
- const bool usePrevFrameBones = animatedModel->PerBoneMotionBlur;
- animatedModel->_skinningData.SetData(bones, !usePrevFrameBones);
- animatedModel->OnAnimUpdate();
+ // Evaluate animated nodes pose
+ graph->GraphExecutor.Update(animatedModel->GraphInstance, dt);
+
+ // Update gameplay
+ animatedModel->OnAnimationUpdated();
}
}
UpdateList.Clear();
@@ -79,6 +81,7 @@ void AnimationManagerService::Update()
void AnimationManagerService::Dispose()
{
UpdateList.Resize(0);
+ UpdateBones.Resize(0);
}
void AnimationManager::AddToUpdate(AnimatedModel* obj)
diff --git a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
index eaa080f9a..22fc6af28 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
+++ b/Source/Engine/Animations/Graph/AnimGraph.Custom.cpp
@@ -10,6 +10,7 @@
#include "Engine/Scripting/ManagedCLR/MUtils.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/MException.h"
+#include "Engine/Content/Assets/SkinnedModel.h"
#include
struct InternalInitData
@@ -144,6 +145,17 @@ void AnimGraphExecutor::ProcessGroupCustom(Box* boxBase, Node* nodeBase, Value&
box->Cache = value;
}
+bool AnimGraph::IsReady() const
+{
+ return BaseModel && BaseModel->IsLoaded();
+}
+
+bool AnimGraph::CanUseWithSkeleton(SkinnedModel* other) const
+{
+ // All data loaded and nodes count the same
+ return IsReady() && other && other->IsLoaded() && other->Skeleton.Nodes.Count() == BaseModel->Skeleton.Nodes.Count();
+}
+
void AnimGraph::ClearCustomNode(Node* node)
{
// Clear data
diff --git a/Source/Engine/Animations/Graph/AnimGraph.cpp b/Source/Engine/Animations/Graph/AnimGraph.cpp
index 2abbb3ff3..2932f7c3f 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.cpp
+++ b/Source/Engine/Animations/Graph/AnimGraph.cpp
@@ -1,8 +1,10 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "AnimGraph.h"
-#include "Engine/Engine/Time.h"
+#include "Engine/Content/Assets/SkinnedModel.h"
+#include "Engine/Graphics/Models/SkeletonData.h"
#include "Engine/Scripting/Scripting.h"
+#include "Engine/Engine/Time.h"
RootMotionData RootMotionData::Identity = { Vector3(0.0f), Quaternion(0.0f, 0.0f, 0.0f, 1.0f) };
@@ -173,7 +175,7 @@ AnimGraphExecutor::AnimGraphExecutor(AnimGraph& graph)
_perGroupProcessCall[16] = (ProcessBoxHandler)&AnimGraphExecutor::ProcessGroupFunction;
}
-const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
+void AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
{
ASSERT(data.Parameters.Count() == _graph.Parameters.Count());
@@ -183,7 +185,6 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
ANIM_GRAPH_PROFILE_EVENT("Init");
// Prepare graph data for the evaluation
- _skeletonBonesCount = skeleton.Bones.Count();
_skeletonNodesCount = skeleton.Nodes.Count();
_graphStack.Clear();
_graphStack.Push((Graph*)&_graph);
@@ -263,23 +264,19 @@ const Matrix* AnimGraphExecutor::Update(AnimGraphInstanceData& data, float dt)
_data->RootMotion = animResult->RootMotion;
}
- // Calculate the final bones transformations
- {
- ANIM_GRAPH_PROFILE_EVENT("Final Pose");
-
- _bonesTransformations.Resize(_skeletonBonesCount, false);
-
- for (int32 boneIndex = 0; boneIndex < _skeletonBonesCount; boneIndex++)
- {
- auto& bone = skeleton.Bones[boneIndex];
- _bonesTransformations[boneIndex] = bone.OffsetMatrix * _data->NodesPose[bone.NodeIndex];
- }
- }
-
// Cleanup
_data = nullptr;
+}
- return _bonesTransformations.Get();
+void AnimGraphExecutor::GetInputValue(Box* box, Value& result)
+{
+ result = eatBox(box->GetParent(), box->FirstConnection());
+}
+
+void AnimGraphExecutor::ResetBucket(int32 bucketIndex)
+{
+ auto& stateBucket = _data->State[bucketIndex];
+ _graph._bucketInitializerList[bucketIndex](stateBucket);
}
void AnimGraphExecutor::ResetBuckets(AnimGraphBase* graph)
diff --git a/Source/Engine/Animations/Graph/AnimGraph.h b/Source/Engine/Animations/Graph/AnimGraph.h
index 714f6e9b8..8ca4b7247 100644
--- a/Source/Engine/Animations/Graph/AnimGraph.h
+++ b/Source/Engine/Animations/Graph/AnimGraph.h
@@ -3,9 +3,9 @@
#pragma once
#include "Engine/Visject/VisjectGraph.h"
-#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Content/Assets/Animation.h"
#include "Engine/Animations/AlphaBlend.h"
+#include "Engine/Core/Math/Matrix.h"
#include "../Config.h"
#define ANIM_GRAPH_PARAM_BASE_MODEL_ID Guid(1000, 0, 0, 0)
@@ -21,6 +21,8 @@ class AnimSubGraph;
class AnimGraphBase;
class AnimGraphNode;
class AnimGraphExecutor;
+class SkinnedModel;
+class SkeletonData;
///
/// The root motion data container. Supports displacement and rotation (no scale component).
@@ -777,22 +779,14 @@ public:
///
/// Determines whether this graph is ready for the animation evaluation.
///
- /// True if is ready and can be used for the animation evaluation, otherwise false.
- bool IsReady() const
- {
- return BaseModel && BaseModel->IsLoaded();
- }
+ bool IsReady() const;
///
/// Determines whether this graph can be used with the specified skeleton.
///
/// The other skinned model to check.
/// True if can perform the update, otherwise false.
- bool CanUseWithSkeleton(SkinnedModel* other) const
- {
- // All data loaded and bones count the same
- return IsReady() && other && other->IsLoaded() && other->Skeleton.Bones.Count() == BaseModel->Skeleton.Bones.Count();
- }
+ bool CanUseWithSkeleton(SkinnedModel* other) const;
private:
@@ -823,12 +817,10 @@ private:
AnimGraph& _graph;
float _deltaTime = 0.0f;
uint64 _currentFrameIndex = 0;
- int32 _skeletonBonesCount = 0;
int32 _skeletonNodesCount = 0;
RootMotionMode _rootMotionMode = RootMotionMode::NoExtraction;
AnimGraphInstanceData* _data = nullptr;
AnimGraphImpulse _emptyNodes;
- Array _bonesTransformations;
AnimGraphTransitionData _transitionData;
Array> _callStack;
Array> _graphStack;
@@ -859,18 +851,13 @@ public:
///
/// The instance data.
/// The delta time (in seconds).
- /// The pointer to the final bones structure as a result of the animation evaluation.
- const Matrix* Update(AnimGraphInstanceData& data, float dt);
+ void Update(AnimGraphInstanceData& data, float dt);
- void GetInputValue(Box* box, Value& result)
- {
- result = eatBox(box->GetParent(), box->FirstConnection());
- }
+ void GetInputValue(Box* box, Value& result);
///
/// Gets the skeleton nodes transformations structure containing identity matrices.
///
- /// The data.
FORCE_INLINE const AnimGraphImpulse* GetEmptyNodes() const
{
return &_emptyNodes;
@@ -920,11 +907,7 @@ public:
/// Resets the state bucket.
///
/// The zero-based index of the bucket.
- FORCE_INLINE void ResetBucket(int32 bucketIndex)
- {
- auto& stateBucket = _data->State[bucketIndex];
- _graph._bucketInitializerList[bucketIndex](stateBucket);
- }
+ void ResetBucket(int32 bucketIndex);
///
/// Resets all the state bucket used by the given graph including sub-graphs (total). Can eb used to reset the animation state of the nested graph (including children).
diff --git a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
index e13714f2c..d7baadfc0 100644
--- a/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
+++ b/Source/Engine/Animations/Graph/AnimGroup.Animation.cpp
@@ -636,7 +636,8 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
transform.Scale = (Vector3)tryGetValue(node->GetBox(4), Vector3::One);
// Skip if no change will be performed
- if (boneIndex < 0 || boneIndex >= _skeletonBonesCount || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
+ auto& skeleton = _graph.BaseModel->Skeleton;
+ if (boneIndex < 0 || boneIndex >= skeleton.Bones.Count() || transformMode == BoneTransformMode::None || (transformMode == BoneTransformMode::Add && transform.IsIdentity()))
{
// Pass through the input
value = Value::Null;
@@ -767,8 +768,9 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
const auto copyScale = (bool)node->Values[4];
// Skip if no change will be performed
- if (srcBoneIndex < 0 || srcBoneIndex >= _skeletonBonesCount ||
- dstBoneIndex < 0 || dstBoneIndex >= _skeletonBonesCount ||
+ const auto& skeleton = _graph.BaseModel->Skeleton;
+ if (srcBoneIndex < 0 || srcBoneIndex >= skeleton.Bones.Count() ||
+ dstBoneIndex < 0 || dstBoneIndex >= skeleton.Bones.Count() ||
!(copyTranslation || copyRotation || copyScale))
{
// Pass through the input
@@ -776,7 +778,6 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
box->Cache = value;
return;
}
- const auto& skeleton = _graph.BaseModel->Skeleton;
// Copy bone data
Transform srcTransform = nodes->Nodes[skeleton.Bones[srcBoneIndex].NodeIndex];
@@ -800,7 +801,7 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
const auto boneIndex = (int32)node->Values[0];
const auto& skeleton = _graph.BaseModel->Skeleton;
const auto input = tryGetValue(node->GetBox(0), Value::Null);
- if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < _skeletonBonesCount)
+ if (ANIM_GRAPH_IS_VALID_PTR(input) && boneIndex >= 0 && boneIndex < skeleton.Bones.Count())
value = Variant(((AnimGraphImpulse*)input.AsPointer)->Nodes[skeleton.Bones[boneIndex].NodeIndex]);
else
value = Variant(Transform::Identity);
diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp
index 1693a8f4d..f669c72c2 100644
--- a/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp
+++ b/Source/Engine/Animations/SceneAnimations/SceneAnimation.cpp
@@ -8,7 +8,7 @@
#include "Engine/Audio/AudioClip.h"
#include "Engine/Graphics/PostProcessSettings.h"
-REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", nullptr, false);
+REGISTER_BINARY_ASSET(SceneAnimation, "FlaxEngine.SceneAnimation", false);
SceneAnimation::SceneAnimation(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
index 784eebb28..7d1cf1a78 100644
--- a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
+++ b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp
@@ -9,6 +9,7 @@
#include "Engine/Serialization/Serialization.h"
#include "Engine/Audio/AudioClip.h"
#include "Engine/Audio/AudioSource.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/Script.h"
diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.h b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.h
index d8934c126..53c311ff6 100644
--- a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.h
+++ b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Level/Actor.h"
+#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Level/Actors/PostFxVolume.h"
#include "SceneAnimation.h"
diff --git a/Source/Engine/Audio/AudioClip.cpp b/Source/Engine/Audio/AudioClip.cpp
index 29dd2a153..3213850d3 100644
--- a/Source/Engine/Audio/AudioClip.cpp
+++ b/Source/Engine/Audio/AudioClip.cpp
@@ -4,6 +4,7 @@
#include "Audio.h"
#include "AudioSource.h"
#include "AudioBackend.h"
+#include "Engine/Core/Log.h"
#include "Engine/Content/Upgraders/AudioClipUpgrader.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Scripting/ManagedCLR/MUtils.h"
@@ -12,7 +13,7 @@
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
#include "Engine/Tools/AudioTool/AudioTool.h"
-REGISTER_BINARY_ASSET(AudioClip, "FlaxEngine.AudioClip", ::New(), false);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(AudioClip, "FlaxEngine.AudioClip", AudioClipUpgrader, false);
bool AudioClip::StreamingTask::Run()
{
diff --git a/Source/Engine/CSG/CSGBuilder.cpp b/Source/Engine/CSG/CSGBuilder.cpp
index b62f2a2f0..ca32862d7 100644
--- a/Source/Engine/CSG/CSGBuilder.cpp
+++ b/Source/Engine/CSG/CSGBuilder.cpp
@@ -7,6 +7,7 @@
#include "Engine/Level/SceneQuery.h"
#include "Engine/Level/Actor.h"
#include "Engine/Core/Log.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Graphics/Models/ModelData.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/Assets/Model.h"
diff --git a/Source/Engine/CSG/HalfEdge.h b/Source/Engine/CSG/HalfEdge.h
index 3a054aff0..e9bd38a34 100644
--- a/Source/Engine/CSG/HalfEdge.h
+++ b/Source/Engine/CSG/HalfEdge.h
@@ -2,6 +2,8 @@
#pragma once
+#include "Engine/Core/Types/BaseTypes.h"
+
namespace CSG
{
///
diff --git a/Source/Engine/Content/Asset.cpp b/Source/Engine/Content/Asset.cpp
index 9bad11533..7fcd2f405 100644
--- a/Source/Engine/Content/Asset.cpp
+++ b/Source/Engine/Content/Asset.cpp
@@ -38,9 +38,10 @@ void Asset::OnDeleteObject()
if (!IsInternalType())
Content::AssetDisposing(this);
- // Cache data
const bool wasMarkedToDelete = _deleteFileOnUnload != 0;
+#if USE_EDITOR
const String path = wasMarkedToDelete ? GetPath() : String::Empty;
+#endif
const Guid id = GetID();
// Fire unload event (every object referencing this asset or it's data should release reference so later actions are safe)
@@ -66,7 +67,7 @@ void Asset::OnDeleteObject()
// Base (after it `this` is invalid)
ManagedScriptingObject::OnDeleteObject();
- // Check if asset was marked to delete
+#if USE_EDITOR
if (wasMarkedToDelete)
{
LOG(Info, "Deleting asset '{0}':{1}.", path, id.ToString());
@@ -77,6 +78,7 @@ void Asset::OnDeleteObject()
// Delete file
Content::deleteFileSafety(path, id);
}
+#endif
}
void Asset::CreateManaged()
@@ -131,6 +133,20 @@ void Asset::ChangeID(const Guid& newId)
CRASH;
}
+bool Asset::LastLoadFailed() const
+{
+ return _loadFailed != 0;
+}
+
+#if USE_EDITOR
+
+bool Asset::ShouldDeleteFileOnUnload() const
+{
+ return _deleteFileOnUnload != 0;
+}
+
+#endif
+
void Asset::Reload()
{
// It's better to call it from the main thread
@@ -335,13 +351,21 @@ void Asset::startLoading()
bool Asset::onLoad(LoadAssetTask* task)
{
// It may fail when task is cancelled and new one is created later (don't crash but just end with an error)
- if (task->GetAsset() != this || _loadingTask == nullptr)
+ if (task->Asset.Get() != this || _loadingTask == nullptr)
return true;
Locker.Lock();
// Load asset
- const LoadResult result = loadAsset();
+ LoadResult result;
+ {
+#if TRACY_ENABLE
+ ZoneScoped;
+ const StringView name(GetPath());
+ ZoneName(*name, name.Length());
+#endif
+ result = loadAsset();
+ }
const bool isLoaded = result == LoadResult::Ok;
const bool failed = !isLoaded;
_loadFailed = failed;
diff --git a/Source/Engine/Content/Asset.h b/Source/Engine/Content/Asset.h
index fb62e659c..a831ee773 100644
--- a/Source/Engine/Content/Asset.h
+++ b/Source/Engine/Content/Asset.h
@@ -82,7 +82,6 @@ public:
///
/// Gets asset's reference count. Asset will be automatically unloaded when this reaches zero.
///
- /// The amount of references to that asset.
API_PROPERTY() int32 GetReferencesCount() const
{
return (int32)Platform::AtomicRead(const_cast(&_refCount));
@@ -107,21 +106,18 @@ public:
public:
///
- /// Gets the path to the asset storage.
+ /// Gets the path to the asset storage file. In Editor it reflects the actual file, in cooked Game, it fakes the Editor path to be informative for developers.
///
- /// The asset file.
API_PROPERTY() virtual const String& GetPath() const = 0;
///
/// Gets the asset type name.
///
- /// The typename.
virtual const String& GetTypeName() const = 0;
///
/// Returns true if asset is loaded, otherwise false.
///
- /// true if this asset is loaded; otherwise, false.
API_PROPERTY() FORCE_INLINE bool IsLoaded() const
{
return _isLoaded != 0;
@@ -130,16 +126,11 @@ public:
///
/// Returns true if last asset loading failed, otherwise false.
///
- /// true if last asset loading failed; otherwise, false.
- API_PROPERTY() FORCE_INLINE bool LastLoadFailed() const
- {
- return _loadFailed != 0;
- }
+ API_PROPERTY() bool LastLoadFailed() const;
///
/// Determines whether this asset is virtual (generated or temporary, has no storage so it won't be saved).
///
- /// true if this asset is virtual; otherwise, false.
API_PROPERTY() FORCE_INLINE bool IsVirtual() const
{
return _isVirtual != 0;
@@ -150,11 +141,7 @@ public:
///
/// Determines whether this asset was marked to be deleted on unload.
///
- /// true if this asset file was marked to be deleted on asset unload; otherwise, false.
- API_PROPERTY() FORCE_INLINE bool ShouldDeleteFileOnUnload() const
- {
- return _deleteFileOnUnload != 0;
- }
+ API_PROPERTY() bool ShouldDeleteFileOnUnload() const;
#endif
diff --git a/Source/Engine/Content/AssetReference.h b/Source/Engine/Content/AssetReference.h
index 40f57337d..0956e82be 100644
--- a/Source/Engine/Content/AssetReference.h
+++ b/Source/Engine/Content/AssetReference.h
@@ -274,3 +274,9 @@ public:
OnSet(asset);
}
};
+
+template
+uint32 GetHash(const AssetReference& key)
+{
+ return GetHash(key.GetID());
+}
diff --git a/Source/Engine/Content/Assets/Animation.cpp b/Source/Engine/Content/Assets/Animation.cpp
index 963ddaceb..d768eabf0 100644
--- a/Source/Engine/Content/Assets/Animation.cpp
+++ b/Source/Engine/Content/Assets/Animation.cpp
@@ -11,7 +11,7 @@
#include "Engine/Serialization/MemoryWriteStream.h"
#endif
-REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", nullptr, false);
+REGISTER_BINARY_ASSET(Animation, "FlaxEngine.Animation", false);
Animation::Animation(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Content/Assets/AnimationGraph.cpp b/Source/Engine/Content/Assets/AnimationGraph.cpp
index 2c0a1c803..7106fb0e0 100644
--- a/Source/Engine/Content/Assets/AnimationGraph.cpp
+++ b/Source/Engine/Content/Assets/AnimationGraph.cpp
@@ -9,7 +9,7 @@
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
-REGISTER_BINARY_ASSET(AnimationGraph, "FlaxEngine.AnimationGraph", nullptr, false);
+REGISTER_BINARY_ASSET(AnimationGraph, "FlaxEngine.AnimationGraph", false);
AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
@@ -74,7 +74,7 @@ BytesContainer AnimationGraph::LoadSurface()
return result;
}
- LOG(Warning, "Animation Graph \'{0}\' surface data is missing.", GetPath());
+ LOG(Warning, "Animation Graph \'{0}\' surface data is missing.", ToString());
return BytesContainer();
}
diff --git a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp
index 7674d93bc..69e611cd4 100644
--- a/Source/Engine/Content/Assets/AnimationGraphFunction.cpp
+++ b/Source/Engine/Content/Assets/AnimationGraphFunction.cpp
@@ -6,7 +6,7 @@
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
-REGISTER_BINARY_ASSET(AnimationGraphFunction, "FlaxEngine.AnimationGraphFunction", nullptr, false);
+REGISTER_BINARY_ASSET(AnimationGraphFunction, "FlaxEngine.AnimationGraphFunction", false);
AnimationGraphFunction::AnimationGraphFunction(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Content/Assets/CubeTexture.cpp b/Source/Engine/Content/Assets/CubeTexture.cpp
index 084955a88..1b9095cab 100644
--- a/Source/Engine/Content/Assets/CubeTexture.cpp
+++ b/Source/Engine/Content/Assets/CubeTexture.cpp
@@ -4,7 +4,7 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
-REGISTER_BINARY_ASSET(CubeTexture, "FlaxEngine.CubeTexture", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(CubeTexture, "FlaxEngine.CubeTexture", TextureAssetUpgrader, true);
CubeTexture::CubeTexture(const SpawnParams& params, const AssetInfo* info)
: TextureBase(params, info)
diff --git a/Source/Engine/Content/Assets/IESProfile.cpp b/Source/Engine/Content/Assets/IESProfile.cpp
index 34f0c59c1..1c1d340be 100644
--- a/Source/Engine/Content/Assets/IESProfile.cpp
+++ b/Source/Engine/Content/Assets/IESProfile.cpp
@@ -4,7 +4,7 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Content/Upgraders/TextureAssetUpgrader.h"
-REGISTER_BINARY_ASSET(IESProfile, "FlaxEngine.IESProfile", ::New(), false);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(IESProfile, "FlaxEngine.IESProfile", TextureAssetUpgrader, false);
IESProfile::IESProfile(const SpawnParams& params, const AssetInfo* info)
: TextureBase(params, info)
diff --git a/Source/Engine/Content/Assets/Material.cpp b/Source/Engine/Content/Assets/Material.cpp
index 4d1e5d283..2be5a6b61 100644
--- a/Source/Engine/Content/Assets/Material.cpp
+++ b/Source/Engine/Content/Assets/Material.cpp
@@ -16,6 +16,9 @@
#include "Engine/Utilities/Encryption.h"
#include "Engine/Tools/MaterialGenerator/MaterialGenerator.h"
#include "Engine/ShadersCompilation/Config.h"
+#if BUILD_DEBUG
+#include "Engine/Engine/Globals.h"
+#endif
#endif
///
@@ -23,7 +26,7 @@
///
#define MATERIAL_AUTO_GENERATE_MISSING_SOURCE (USE_EDITOR)
-REGISTER_BINARY_ASSET(Material, "FlaxEngine.Material", ::New(), false);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(Material, "FlaxEngine.Material", ShaderAssetUpgrader, false);
Material::Material(const SpawnParams& params, const AssetInfo* info)
: ShaderAssetTypeBase(params, info)
@@ -116,7 +119,7 @@ Asset::LoadResult Material::load()
FlaxChunk* materialParamsChunk;
// Special case for Null renderer
- if (GPUDevice::Instance->GetRendererType() == RendererType::Null)
+ if (IsNullRenderer())
{
// Hack loading
MemoryReadStream shaderCacheStream(nullptr, 0);
@@ -152,18 +155,16 @@ Asset::LoadResult Material::load()
// - If material version is not supported then material cannot be loaded
#if COMPILE_WITH_SHADER_COMPILER
-#if BUILD_DEBUG
- // Materials force reload!
- Globals::ConvertLoadedMaterialsByForce = false;
-#endif
-
// Check if current engine has different materials version or convert it by force or has no source generated at all
if (_shaderHeader.Material.GraphVersion != MATERIAL_GRAPH_VERSION
- || Globals::ConvertLoadedMaterialsByForce
#if MATERIAL_AUTO_GENERATE_MISSING_SOURCE
|| !HasChunk(SHADER_FILE_CHUNK_SOURCE)
#endif
|| HasDependenciesModified()
+#if COMPILE_WITH_DEV_ENV
+ // Set to true to enable force GPU shader regeneration (don't commit it)
+ || false
+#endif
)
{
// Prepare
@@ -310,7 +311,12 @@ Asset::LoadResult Material::load()
{
// Load material (load shader from cache, load params, setup pipeline stuff)
MemoryReadStream shaderCacheStream(shaderCache.Data.Get(), shaderCache.Data.Length());
- _materialShader = MaterialShader::Create(GetPath(), shaderCacheStream, _shaderHeader.Material.Info);
+#if GPU_ENABLE_RESOURCE_NAMING
+ const StringView name(GetPath());
+#else
+ const StringView name;
+#endif
+ _materialShader = MaterialShader::Create(name, shaderCacheStream, _shaderHeader.Material.Info);
if (_materialShader == nullptr)
{
LOG(Warning, "Cannot load material.");
@@ -482,7 +488,7 @@ BytesContainer Material::LoadSurface(bool createDefaultIfMissing)
}
}
- LOG(Warning, "Material \'{0}\' surface data is missing.", GetPath());
+ LOG(Warning, "Material \'{0}\' surface data is missing.", ToString());
#if COMPILE_WITH_MATERIAL_GRAPH
diff --git a/Source/Engine/Content/Assets/MaterialFunction.cpp b/Source/Engine/Content/Assets/MaterialFunction.cpp
index 97af31960..ca3cc58fb 100644
--- a/Source/Engine/Content/Assets/MaterialFunction.cpp
+++ b/Source/Engine/Content/Assets/MaterialFunction.cpp
@@ -8,7 +8,7 @@
#endif
#include "Engine/Content/Factories/BinaryAssetFactory.h"
-REGISTER_BINARY_ASSET(MaterialFunction, "FlaxEngine.MaterialFunction", nullptr, false);
+REGISTER_BINARY_ASSET(MaterialFunction, "FlaxEngine.MaterialFunction", false);
MaterialFunction::MaterialFunction(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Content/Assets/MaterialInstance.cpp b/Source/Engine/Content/Assets/MaterialInstance.cpp
index 874f607ce..5ea8c9351 100644
--- a/Source/Engine/Content/Assets/MaterialInstance.cpp
+++ b/Source/Engine/Content/Assets/MaterialInstance.cpp
@@ -7,7 +7,7 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Serialization/MemoryReadStream.h"
-REGISTER_BINARY_ASSET(MaterialInstance, "FlaxEngine.MaterialInstance", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(MaterialInstance, "FlaxEngine.MaterialInstance", MaterialInstanceUpgrader, true);
MaterialInstance::MaterialInstance(const SpawnParams& params, const AssetInfo* info)
: MaterialBase(params, info)
diff --git a/Source/Engine/Content/Assets/Model.cpp b/Source/Engine/Content/Assets/Model.cpp
index d6e8f1809..dd9c484e1 100644
--- a/Source/Engine/Content/Assets/Model.cpp
+++ b/Source/Engine/Content/Assets/Model.cpp
@@ -8,9 +8,11 @@
#include "Engine/Content/Upgraders/ModelAssetUpgrader.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Graphics/RenderTools.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
#include "Engine/Streaming/StreamingGroup.h"
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
+#include "Engine/Renderer/DrawCall.h"
#if GPU_ENABLE_ASYNC_RESOURCES_CREATION
#include "Engine/Threading/ThreadPoolTask.h"
#define STREAM_TASK_BASE ThreadPoolTask
@@ -113,7 +115,7 @@ protected:
}
};
-REGISTER_BINARY_ASSET(Model, "FlaxEngine.Model", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(Model, "FlaxEngine.Model", ModelAssetUpgrader, true);
Model::Model(const SpawnParams& params, const AssetInfo* info)
: ModelBase(params, info, StreamingGroups::Instance()->Models())
@@ -819,7 +821,7 @@ Asset::LoadResult Model::load()
const auto thisSS = LODs[lodIndex].ScreenSize;
if (prevSS <= thisSS)
{
- LOG(Warning, "Model LOD {0} has invalid screen size compared to LOD {1} (asset: {2})", lodIndex, lodIndex - 1, GetPath());
+ LOG(Warning, "Model LOD {0} has invalid screen size compared to LOD {1} (asset: {2})", lodIndex, lodIndex - 1, ToString());
}
}
#endif
diff --git a/Source/Engine/Content/Assets/RawDataAsset.cpp b/Source/Engine/Content/Assets/RawDataAsset.cpp
index f93395579..98b9e3251 100644
--- a/Source/Engine/Content/Assets/RawDataAsset.cpp
+++ b/Source/Engine/Content/Assets/RawDataAsset.cpp
@@ -4,7 +4,7 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Platform/FileSystem.h"
-REGISTER_BINARY_ASSET(RawDataAsset, "FlaxEngine.RawDataAsset", nullptr, true);
+REGISTER_BINARY_ASSET(RawDataAsset, "FlaxEngine.RawDataAsset", true);
RawDataAsset::RawDataAsset(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Content/Assets/Shader.cpp b/Source/Engine/Content/Assets/Shader.cpp
index 929abc933..3f54eadbf 100644
--- a/Source/Engine/Content/Assets/Shader.cpp
+++ b/Source/Engine/Content/Assets/Shader.cpp
@@ -2,11 +2,13 @@
#include "Shader.h"
#include "Engine/Core/Log.h"
+#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Content/Upgraders/ShaderAssetUpgrader.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Serialization/MemoryReadStream.h"
-REGISTER_BINARY_ASSET(Shader, "FlaxEngine.Shader", ::New(), false);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(Shader, "FlaxEngine.Shader", ShaderAssetUpgrader, false);
Shader::Shader(const SpawnParams& params, const AssetInfo* info)
: ShaderAssetTypeBase(params, info)
@@ -25,7 +27,7 @@ Shader::~Shader()
Asset::LoadResult Shader::load()
{
// Special case for Null renderer that doesn't need shaders
- if (GPUDevice::Instance->GetRendererType() == RendererType::Null)
+ if (IsNullRenderer())
{
return LoadResult::Ok;
}
diff --git a/Source/Engine/Content/Assets/Shader.h b/Source/Engine/Content/Assets/Shader.h
index b97aafd98..9efdf8d6d 100644
--- a/Source/Engine/Content/Assets/Shader.h
+++ b/Source/Engine/Content/Assets/Shader.h
@@ -3,9 +3,10 @@
#pragma once
#include "../BinaryAsset.h"
-#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Graphics/Shaders/Cache/ShaderAssetBase.h"
+class GPUShader;
+
///
/// The shader asset. Contains a program that runs on the GPU and is able to perform rendering calculation using textures, vertices and other resources.
///
@@ -33,7 +34,6 @@ public:
///
/// Gets the GPU shader object.
///
- /// The GPU shader object.
FORCE_INLINE GPUShader* GetShader() const
{
return GPU;
diff --git a/Source/Engine/Content/Assets/SkeletonMask.cpp b/Source/Engine/Content/Assets/SkeletonMask.cpp
index 0742e2951..27529df4d 100644
--- a/Source/Engine/Content/Assets/SkeletonMask.cpp
+++ b/Source/Engine/Content/Assets/SkeletonMask.cpp
@@ -7,7 +7,7 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Content/Upgraders/SkeletonMaskUpgrader.h"
-REGISTER_BINARY_ASSET(SkeletonMask, "FlaxEngine.SkeletonMask", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(SkeletonMask, "FlaxEngine.SkeletonMask", SkeletonMaskUpgrader, true);
SkeletonMask::SkeletonMask(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Content/Assets/SkinnedModel.cpp b/Source/Engine/Content/Assets/SkinnedModel.cpp
index 7c498b8e8..b98ba2e57 100644
--- a/Source/Engine/Content/Assets/SkinnedModel.cpp
+++ b/Source/Engine/Content/Assets/SkinnedModel.cpp
@@ -7,12 +7,14 @@
#include "Engine/Streaming/StreamingGroup.h"
#include "Engine/Threading/ThreadPoolTask.h"
#include "Engine/Graphics/RenderTools.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Models/ModelInstanceEntry.h"
#include "Engine/Graphics/Models/Config.h"
#include "Engine/Content/WeakAssetReference.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h"
#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
+#include "Engine/Renderer/DrawCall.h"
#define CHECK_INVALID_BUFFER(buffer) \
if (buffer->IsValidFor(this) == false) \
@@ -106,7 +108,7 @@ protected:
}
};
-REGISTER_BINARY_ASSET(SkinnedModel, "FlaxEngine.SkinnedModel", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(SkinnedModel, "FlaxEngine.SkinnedModel", SkinnedModelAssetUpgrader, true);
SkinnedModel::SkinnedModel(const SpawnParams& params, const AssetInfo* info)
: ModelBase(params, info, StreamingGroups::Instance()->SkinnedModels())
@@ -120,6 +122,11 @@ SkinnedModel::~SkinnedModel()
ASSERT(_streamingTask == nullptr);
}
+bool SkinnedModel::HasAnyLODInitialized() const
+{
+ return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized();
+}
+
Array SkinnedModel::GetBlendShapes()
{
Array result;
diff --git a/Source/Engine/Content/Assets/SkinnedModel.h b/Source/Engine/Content/Assets/SkinnedModel.h
index 0dabcef05..08cbf23b0 100644
--- a/Source/Engine/Content/Assets/SkinnedModel.h
+++ b/Source/Engine/Content/Assets/SkinnedModel.h
@@ -64,7 +64,6 @@ public:
///
/// Gets the amount of loaded model LODs.
///
- /// Loaded LODs count
API_PROPERTY() FORCE_INLINE int32 GetLoadedLODs() const
{
return _loadedLODs;
@@ -93,7 +92,6 @@ public:
///
/// Gets index of the highest resident LOD (may be equal to LODs.Count if no LOD has been uploaded). Note: LOD=0 is the highest (top quality)
///
- /// LOD index
FORCE_INLINE int32 HighestResidentLODIndex() const
{
return GetLODsCount() - _loadedLODs;
@@ -103,10 +101,7 @@ public:
/// Determines whether any LOD has been initialized.
///
/// True if any LOD has been initialized, otherwise false.
- FORCE_INLINE bool HasAnyLODInitialized() const
- {
- return LODs.HasItems() && LODs.Last().HasAnyMeshInitialized();
- }
+ bool HasAnyLODInitialized() const;
///
/// Determines whether this model can be rendered.
diff --git a/Source/Engine/Content/Assets/Texture.cpp b/Source/Engine/Content/Assets/Texture.cpp
index 22c86028a..23dbff0e2 100644
--- a/Source/Engine/Content/Assets/Texture.cpp
+++ b/Source/Engine/Content/Assets/Texture.cpp
@@ -10,7 +10,7 @@
#include "Engine/Scripting/MainThreadManagedInvokeAction.h"
#include "Engine/Tools/TextureTool/TextureTool.h"
-REGISTER_BINARY_ASSET(Texture, "FlaxEngine.Texture", ::New(), true);
+REGISTER_BINARY_ASSET_WITH_UPGRADER(Texture, "FlaxEngine.Texture", TextureAssetUpgrader, true);
Texture::Texture(const SpawnParams& params, const AssetInfo* info)
: TextureBase(params, info)
diff --git a/Source/Engine/Content/Assets/VisualScript.cpp b/Source/Engine/Content/Assets/VisualScript.cpp
index 5fd9d6f3f..2da76a840 100644
--- a/Source/Engine/Content/Assets/VisualScript.cpp
+++ b/Source/Engine/Content/Assets/VisualScript.cpp
@@ -17,6 +17,7 @@
#include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Serialization/JsonWriter.h"
+#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Utilities/StringConverter.h"
#include "FlaxEngine.Gen.h"
@@ -1276,7 +1277,7 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
}
}
-REGISTER_BINARY_ASSET(VisualScript, "FlaxEngine.VisualScript", nullptr, false);
+REGISTER_BINARY_ASSET(VisualScript, "FlaxEngine.VisualScript", false);
VisualScript::VisualScript(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
@@ -1329,6 +1330,7 @@ Asset::LoadResult VisualScript::load()
{
case GRAPH_NODE_MAKE_TYPE(16, 3):
{
+ // Override method
auto& method = _methods.AddOne();
method.Script = this;
method.Node = &node;
@@ -1342,6 +1344,7 @@ Asset::LoadResult VisualScript::load()
}
case GRAPH_NODE_MAKE_TYPE(16, 6):
{
+ // Function
auto& method = _methods.AddOne();
method.Script = this;
method.Node = &node;
@@ -1380,6 +1383,17 @@ Asset::LoadResult VisualScript::load()
}
}
}
+#if COMPILE_WITH_PROFILER
+ for (auto& method : _methods)
+ {
+ const StringView assetName(StringUtils::GetFileNameWithoutExtension(GetPath()));
+ method.ProfilerName.Resize(assetName.Length() + 2 + method.Name.Length());
+ StringUtils::ConvertUTF162ANSI(assetName.Get(), method.ProfilerName.Get(), assetName.Length());
+ method.ProfilerName.Get()[assetName.Length()] = ':';
+ method.ProfilerName.Get()[assetName.Length() + 1] = ':';
+ Platform::MemoryCopy(method.ProfilerName.Get() + assetName.Length() + 2, method.Name.Get(), method.Name.Length());
+ }
+#endif
// Setup fields list
_fields.Resize(Graph.Parameters.Count());
@@ -2132,7 +2146,7 @@ BytesContainer VisualScript::LoadSurface()
return result;
}
- LOG(Warning, "\'{0}\' surface data is missing.", GetPath());
+ LOG(Warning, "\'{0}\' surface data is missing.", ToString());
return BytesContainer();
}
@@ -2284,6 +2298,7 @@ VisualScriptingBinaryModule* VisualScripting::GetBinaryModule()
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span parameters)
{
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
+ PROFILE_CPU_NAMED(*method->ProfilerName);
// Add to the calling stack
ScopeContext scope;
diff --git a/Source/Engine/Content/Assets/VisualScript.h b/Source/Engine/Content/Assets/VisualScript.h
index 6beeca5cc..1a1201191 100644
--- a/Source/Engine/Content/Assets/VisualScript.h
+++ b/Source/Engine/Content/Assets/VisualScript.h
@@ -115,6 +115,9 @@ public:
MethodFlags MethodFlags;
ScriptingTypeMethodSignature Signature;
Array> ParamNames;
+#if COMPILE_WITH_PROFILER
+ StringAnsi ProfilerName;
+#endif
};
struct Field
diff --git a/Source/Engine/Content/BinaryAsset.cpp b/Source/Engine/Content/BinaryAsset.cpp
index baa065698..ef22bd3c9 100644
--- a/Source/Engine/Content/BinaryAsset.cpp
+++ b/Source/Engine/Content/BinaryAsset.cpp
@@ -132,6 +132,13 @@ void BinaryAsset::GetImportMetadata(String& path, String& username) const
}
}
+String BinaryAsset::GetImportPath() const
+{
+ String path, username;
+ GetImportMetadata(path, username);
+ return path;
+}
+
void BinaryAsset::ClearDependencies()
{
for (auto& e : Dependencies)
@@ -294,7 +301,12 @@ bool BinaryAsset::LoadChunks(AssetChunksFlag chunks)
#if USE_EDITOR
-bool BinaryAsset::SaveAsset(const StringView& path, AssetInitData& data, bool silentMode)
+bool BinaryAsset::SaveAsset(AssetInitData& data, bool silentMode) const
+{
+ return SaveAsset(GetPath(), data, silentMode);
+}
+
+bool BinaryAsset::SaveAsset(const StringView& path, AssetInitData& data, bool silentMode) const
{
data.Header = _header;
data.Metadata.Link(Metadata);
@@ -434,7 +446,12 @@ void BinaryAsset::OnDeleteObject()
const String& BinaryAsset::GetPath() const
{
+#if USE_EDITOR
return Storage ? Storage->GetPath() : String::Empty;
+#else
+ // In build all assets are packed into packages so use ID for original path lookup
+ return Content::GetRegistry()->GetEditorAssetPath(_id);
+#endif
}
///
@@ -492,7 +509,6 @@ protected:
return Result::Ok;
}
-
void OnEnd() override
{
_dataLock.Release();
diff --git a/Source/Engine/Content/BinaryAsset.h b/Source/Engine/Content/BinaryAsset.h
index c533399d2..207faadfa 100644
--- a/Source/Engine/Content/BinaryAsset.h
+++ b/Source/Engine/Content/BinaryAsset.h
@@ -109,13 +109,7 @@ public:
///
/// Gets the imported file path from the asset metadata (can be empty if not available).
///
- /// The imported source file path.
- API_PROPERTY() String GetImportPath() const
- {
- String path, username;
- GetImportMetadata(path, username);
- return path;
- }
+ API_PROPERTY() String GetImportPath() const;
///
/// Clears the asset dependencies list and unregisters from tracking their changes.
@@ -131,7 +125,6 @@ public:
///
/// Determines whether any of the dependency assets was modified after last modification time of this asset (last file write time check).
///
- /// true if one or more dependencies were modified; otherwise, false.
bool HasDependenciesModified() const;
protected:
@@ -277,10 +270,7 @@ public:
/// Asset data.
/// In silent mode don't reload opened storage container that is using target file.
/// True if failed, otherwise false.
- FORCE_INLINE bool SaveAsset(AssetInitData& data, bool silentMode = false)
- {
- return SaveAsset(GetPath(), data, silentMode);
- }
+ bool SaveAsset(AssetInitData& data, bool silentMode = false) const;
///
/// Saves this asset to the file.
@@ -289,7 +279,7 @@ public:
/// Asset path (will be used to override the asset or create a new one).
/// In silent mode don't reload opened storage container that is using target file.
/// True if failed, otherwise false.
- bool SaveAsset(const StringView& path, AssetInitData& data, bool silentMode = false);
+ bool SaveAsset(const StringView& path, AssetInitData& data, bool silentMode = false) const;
///
/// Saves asset data to the storage container. Asset unique ID is handled by auto.
diff --git a/Source/Engine/Content/Cache/AssetsCache.cpp b/Source/Engine/Content/Cache/AssetsCache.cpp
index 71faef533..35863be60 100644
--- a/Source/Engine/Content/Cache/AssetsCache.cpp
+++ b/Source/Engine/Content/Cache/AssetsCache.cpp
@@ -3,6 +3,7 @@
#include "AssetsCache.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/DeleteMe.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Serialization/FileWriteStream.h"
#include "Engine/Serialization/FileReadStream.h"
@@ -10,12 +11,12 @@
#include "Engine/Content/Storage/ContentStorageManager.h"
#include "Engine/Content/Storage/JsonStorageProxy.h"
#include "Engine/Profiler/ProfilerCPU.h"
+#include "Engine/Engine/Globals.h"
#include "FlaxEngine.Gen.h"
AssetsCache::AssetsCache()
: _isDirty(false)
, _registry(4096)
- , _pathsMapping(256)
{
}
@@ -91,8 +92,8 @@ void AssetsCache::Init()
#if ENABLE_ASSETS_DISCOVERY
stream->Read(&e.FileModified);
#else
- DateTime tmp1;
- stream->Read(&tmp1);
+ DateTime tmp1;
+ stream->Read(&tmp1);
#endif
if (flags & AssetsCacheFlags::RelativePaths && e.Info.Path.HasChars())
@@ -207,7 +208,7 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
#if ENABLE_ASSETS_DISCOVERY
stream->Write(&e.FileModified);
#else
- stream->WriteInt64(0);
+ stream->WriteInt64(0);
#endif
index++;
@@ -231,6 +232,21 @@ bool AssetsCache::Save(const StringView& path, const Registry& entries, const Pa
return false;
}
+const String& AssetsCache::GetEditorAssetPath(const Guid& id) const
+{
+#if USE_EDITOR
+ auto e = _registry.TryGet(id);
+ return e ? e->Info.Path : String::Empty;
+#else
+ for (auto& e : _pathsMapping)
+ {
+ if (e.Value == id)
+ return e.Key;
+ }
+ return String::Empty;
+#endif
+}
+
bool AssetsCache::FindAsset(const StringView& path, AssetInfo& info)
{
PROFILE_CPU();
@@ -402,41 +418,55 @@ void AssetsCache::RegisterAssets(FlaxStorage* storage)
_isDirty = true;
}
+void AssetsCache::RegisterAsset(const AssetHeader& header, const StringView& path)
+{
+ RegisterAsset(header.ID, header.TypeName, path);
+}
+
+void AssetsCache::RegisterAssets(const FlaxStorageReference& storage)
+{
+ RegisterAssets(storage.Get());
+}
+
void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const StringView& path)
{
PROFILE_CPU();
-
ScopeLock lock(_locker);
- // Mark registry as draft
- _isDirty = true;
-
// Check if asset has been already added to the registry
bool isMissing = true;
for (auto i = _registry.Begin(); i.IsNotEnd(); ++i)
{
auto& e = i->Value;
- // Compare IDs
if (e.Info.ID == id)
{
- // Update registry entry
- e.Info.Path = path;
- e.Info.TypeName = typeName;
-
- // Back
+ if (e.Info.Path != path)
+ {
+ e.Info.Path = path;
+ _isDirty = true;
+ }
+ if (e.Info.TypeName != typeName)
+ {
+ e.Info.TypeName = typeName;
+ _isDirty = true;
+ }
isMissing = false;
break;
}
- // Compare paths
if (e.Info.Path == path)
{
- // Update registry entry
- e.Info.ID = id;
- e.Info.TypeName = typeName;
-
- // Back
+ if (e.Info.ID != id)
+ {
+ e.Info.Path = path;
+ _isDirty = true;
+ }
+ if (e.Info.TypeName != typeName)
+ {
+ e.Info.TypeName = typeName;
+ _isDirty = true;
+ }
isMissing = false;
break;
}
@@ -445,9 +475,8 @@ void AssetsCache::RegisterAsset(const Guid& id, const String& typeName, const St
if (isMissing)
{
LOG(Info, "Register asset {0}:{1} \'{2}\'", id, typeName, path);
-
- // Add new asset entry
_registry.Add(id, Entry(id, typeName, path));
+ _isDirty = true;
}
}
@@ -567,8 +596,8 @@ bool AssetsCache::IsEntryValid(Entry& e)
#else
// In game we don't care about it because all cached asset entries are valid (precached)
- // Skip only entries with missing file
- return e.Info.Path.HasChars();
+ // Skip only entries with missing file
+ return e.Info.Path.HasChars();
#endif
}
diff --git a/Source/Engine/Content/Cache/AssetsCache.h b/Source/Engine/Content/Cache/AssetsCache.h
index 3186b3cfc..cee2e0e8f 100644
--- a/Source/Engine/Content/Cache/AssetsCache.h
+++ b/Source/Engine/Content/Cache/AssetsCache.h
@@ -2,13 +2,19 @@
#pragma once
+#include "../AssetInfo.h"
+#include "../Config.h"
#include "Engine/Core/Types/Guid.h"
+#if ENABLE_ASSETS_DISCOVERY
+#include "Engine/Core/Types/DateTime.h"
+#endif
#include "Engine/Core/Types/String.h"
#include "Engine/Core/Collections/Dictionary.h"
#include "Engine/Platform/CriticalSection.h"
-#include "Engine/Content/Storage/FlaxStorageReference.h"
-#include "../AssetInfo.h"
-#include "../Config.h"
+
+struct AssetHeader;
+struct FlaxStorageReference;
+class FlaxStorage;
///
/// Assets cache flags.
@@ -46,19 +52,17 @@ public:
AssetInfo Info;
#if ENABLE_ASSETS_DISCOVERY
-
///
/// The file modified date.
///
DateTime FileModified;
-
#endif
Entry()
{
}
- Entry(const Guid& id, const String& typeName, const StringView& path)
+ Entry(const Guid& id, const StringView& typeName, const StringView& path)
: Info(id, typeName, path)
#if ENABLE_ASSETS_DISCOVERY
, FileModified(DateTime::NowUTC())
@@ -124,6 +128,13 @@ public:
public:
+ ///
+ /// Finds the asset path by id. In editor it returns the actual asset path, at runtime it returns the mapped asset path.
+ ///
+ /// The asset id.
+ /// The asset path, or empty if failed to find.
+ const String& GetEditorAssetPath(const Guid& id) const;
+
///
/// Finds the asset info by path.
///
@@ -167,16 +178,13 @@ public:
///
/// The asset typename.
/// The result array.
- void GetAllByTypeName(const StringView& typeName, Array& result) const;
+ void GetAllByTypeName(const StringView& typeName, Array& result) const;
///
/// Register assets in the cache
///
/// Flax assets container reference
- FORCE_INLINE void RegisterAssets(const FlaxStorageReference& storage)
- {
- RegisterAssets(storage.Get());
- }
+ void RegisterAssets(const FlaxStorageReference& storage);
///
/// Register assets in the cache
@@ -189,10 +197,7 @@ public:
///
/// Flax asset file header
/// Asset path
- FORCE_INLINE void RegisterAsset(const AssetHeader& header, const StringView& path)
- {
- RegisterAsset(header.ID, header.TypeName, path);
- }
+ void RegisterAsset(const AssetHeader& header, const StringView& path);
///
/// Register asset in the cache
diff --git a/Source/Engine/Content/Content.cpp b/Source/Engine/Content/Content.cpp
index 493147355..0b3f9a1d7 100644
--- a/Source/Engine/Content/Content.cpp
+++ b/Source/Engine/Content/Content.cpp
@@ -14,6 +14,7 @@
#include "Engine/Threading/Threading.h"
#include "Engine/Graphics/Graphics.h"
#include "Engine/Engine/Time.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Level/Types.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
diff --git a/Source/Engine/Content/Factories/BinaryAssetFactory.cpp b/Source/Engine/Content/Factories/BinaryAssetFactory.cpp
index c3c4e8178..220ea5ed5 100644
--- a/Source/Engine/Content/Factories/BinaryAssetFactory.cpp
+++ b/Source/Engine/Content/Factories/BinaryAssetFactory.cpp
@@ -4,6 +4,7 @@
#include "../BinaryAsset.h"
#include "Engine/Core/Log.h"
#include "Engine/Core/Math/Math.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Content/Storage/ContentStorageManager.h"
#if USE_EDITOR
@@ -14,28 +15,23 @@
bool BinaryAssetFactoryBase::Init(BinaryAsset* asset)
{
ASSERT(asset && asset->Storage);
-
- // Prepare
auto storage = asset->Storage;
- AssetInfo info;
- info.ID = asset->GetID();
- info.TypeName = asset->GetTypeName();
- info.Path = storage->GetPath();
// Load serialized asset data
AssetInitData initData;
- if (storage->LoadAssetHeader(info.ID, initData))
+ if (storage->LoadAssetHeader(asset->GetID(), initData))
{
- LOG(Error, "Cannot load asset header.\nInfo: {0}", info.ToString());
+ LOG(Error, "Cannot load asset header.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString());
return true;
}
-#if COMPILE_WITH_ASSET_UPGRADERS
+#if USE_EDITOR
// Check if need to perform data conversion to the newer version (only in Editor)
const auto upgrader = GetUpgrader();
if (storage->AllowDataModifications() && upgrader && upgrader->ShouldUpgrade(initData.SerializedVersion))
{
const auto startTime = DateTime::NowUTC();
+ const AssetInfo info(asset->GetID(), asset->GetTypeName(), storage->GetPath());
LOG(Info, "Starting asset \'{0}\' conversion", info.Path);
// Backup source file (in case of conversion failure)
@@ -99,21 +95,21 @@ bool BinaryAssetFactoryBase::Init(BinaryAsset* asset)
// Check if serialized asset version is supported
if (!IsVersionSupported(initData.SerializedVersion))
{
- LOG(Warning, "Asset version {1} is not supported.\nInfo: {0}", info.ToString(), initData.SerializedVersion);
+ LOG(Warning, "Asset version {1} is not supported.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString(), initData.SerializedVersion);
return true;
}
// Initialize asset
if (asset->Init(initData))
{
- LOG(Error, "Cannot initialize asset.\nInfo: {0}", info.ToString());
+ LOG(Error, "Cannot initialize asset.\nInfo: {0}", AssetInfo(asset->GetID(), asset->GetTypeName(), storage->GetPath()).ToString());
return true;
}
return false;
}
-#if COMPILE_WITH_ASSET_UPGRADERS
+#if USE_EDITOR
bool BinaryAssetFactoryBase::UpgradeAsset(const AssetInfo& info, FlaxStorage* storage, AssetMigrationContext& context)
{
diff --git a/Source/Engine/Content/Factories/BinaryAssetFactory.h b/Source/Engine/Content/Factories/BinaryAssetFactory.h
index 25dd38aeb..1040ea3c5 100644
--- a/Source/Engine/Content/Factories/BinaryAssetFactory.h
+++ b/Source/Engine/Content/Factories/BinaryAssetFactory.h
@@ -3,7 +3,9 @@
#pragma once
#include "IAssetFactory.h"
+#if USE_EDITOR
#include "Engine/Content/Upgraders/BinaryAssetUpgrader.h"
+#endif
#include "Engine/Content/AssetInfo.h"
#include "Engine/Scripting/ScriptingObject.h"
@@ -14,7 +16,7 @@ class FlaxStorage;
/// The binary assets factory base class.
///
///
-class BinaryAssetFactoryBase : public IAssetFactory
+class FLAXENGINE_API BinaryAssetFactoryBase : public IAssetFactory
{
public:
@@ -29,7 +31,7 @@ protected:
virtual BinaryAsset* Create(const AssetInfo& info) = 0;
virtual bool IsVersionSupported(uint32 serializedVersion) const = 0;
-#if COMPILE_WITH_ASSET_UPGRADERS
+#if USE_EDITOR
bool UpgradeAsset(const AssetInfo& info, FlaxStorage* storage, AssetMigrationContext& context);
#endif
@@ -65,16 +67,31 @@ protected:
}
};
-#define REGISTER_BINARY_ASSET(type, typeName, upgrader, supportsVirtualAssets) \
+#define REGISTER_BINARY_ASSET(type, typeName, supportsVirtualAssets) \
+ const String type::TypeName = TEXT(typeName); \
+ class CONCAT_MACROS(Factory, type) : public BinaryAssetFactory \
+ { \
+ public: \
+ CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
+ ~CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Remove(type::TypeName); } \
+ bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
+ }; \
+ static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
+
+#if USE_EDITOR
+#define REGISTER_BINARY_ASSET_WITH_UPGRADER(type, typeName, upgrader, supportsVirtualAssets) \
const String type::TypeName = TEXT(typeName); \
class CONCAT_MACROS(Factory, type) : public BinaryAssetFactory \
{ \
private: \
- IAssetUpgrader* _upgrader = upgrader; \
+ IAssetUpgrader* _upgrader = ::New(); \
public: \
CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
- ~CONCAT_MACROS(Factory, type)() { if (_upgrader) Delete(_upgrader); IAssetFactory::Get().Remove(type::TypeName); } \
+ ~CONCAT_MACROS(Factory, type)() { Delete(_upgrader); IAssetFactory::Get().Remove(type::TypeName); } \
bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
IAssetUpgrader* GetUpgrader() const override { return _upgrader; } \
}; \
static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
+#else
+#define REGISTER_BINARY_ASSET_WITH_UPGRADER(type, typeName, upgrader, supportsVirtualAssets) REGISTER_BINARY_ASSET(type, typeName, supportsVirtualAssets)
+#endif
diff --git a/Source/Engine/Content/Factories/IAssetFactory.h b/Source/Engine/Content/Factories/IAssetFactory.h
index dbc7b1e90..a4f5681b4 100644
--- a/Source/Engine/Content/Factories/IAssetFactory.h
+++ b/Source/Engine/Content/Factories/IAssetFactory.h
@@ -9,13 +9,10 @@ struct AssetInfo;
class Asset;
class IAssetUpgrader;
-// Enables upgrading asset files from the older version format
-#define COMPILE_WITH_ASSET_UPGRADERS (USE_EDITOR)
-
///
/// The asset objects factory.
///
-class IAssetFactory
+class FLAXENGINE_API IAssetFactory
{
public:
diff --git a/Source/Engine/Content/Factories/JsonAssetFactory.h b/Source/Engine/Content/Factories/JsonAssetFactory.h
index 0269ec596..988776186 100644
--- a/Source/Engine/Content/Factories/JsonAssetFactory.h
+++ b/Source/Engine/Content/Factories/JsonAssetFactory.h
@@ -10,7 +10,7 @@
/// The Json assets factory base class.
///
///
-class JsonAssetFactoryBase : public IAssetFactory
+class FLAXENGINE_API JsonAssetFactoryBase : public IAssetFactory
{
protected:
@@ -23,7 +23,6 @@ public:
{
return Create(info);
}
-
Asset* NewVirtual(const AssetInfo& info) override
{
return Create(info);
@@ -47,12 +46,13 @@ protected:
}
};
-#define REGISTER_JSON_ASSET(type, typeName) \
+#define REGISTER_JSON_ASSET(type, typeName, supportsVirtualAssets) \
const String type::TypeName = TEXT(typeName); \
class CONCAT_MACROS(Factory, type) : public JsonAssetFactory \
{ \
public: \
CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Add(type::TypeName, this); } \
~CONCAT_MACROS(Factory, type)() { IAssetFactory::Get().Remove(type::TypeName); } \
+ bool SupportsVirtualAssets() const override { return supportsVirtualAssets; } \
}; \
static CONCAT_MACROS(Factory, type) CONCAT_MACROS(CFactory, type)
diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp
index 821c43f87..44baecb12 100644
--- a/Source/Engine/Content/JsonAsset.cpp
+++ b/Source/Engine/Content/JsonAsset.cpp
@@ -1,12 +1,16 @@
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
#include "JsonAsset.h"
-#include "Storage/ContentStorageManager.h"
#include "Engine/Threading/Threading.h"
#if USE_EDITOR
#include "Engine/Platform/File.h"
+#include "Engine/Core/Types/DataContainer.h"
+#else
+#include "Storage/ContentStorageManager.h"
#endif
+#include "Content.h"
#include "FlaxEngine.Gen.h"
+#include "Cache/AssetsCache.h"
#include "Engine/Core/Log.h"
#include "Engine/Serialization/JsonTools.h"
#include "Engine/Content/Factories/JsonAssetFactory.h"
@@ -38,7 +42,12 @@ String JsonAssetBase::GetData() const
const String& JsonAssetBase::GetPath() const
{
+#if USE_EDITOR
return _path;
+#else
+ // In build all assets are packed into packages so use ID for original path lookup
+ return Content::GetRegistry()->GetEditorAssetPath(_id);
+#endif
}
#if USE_EDITOR
@@ -93,9 +102,8 @@ Asset::LoadResult JsonAssetBase::loadAsset()
{
// Load data (raw json file in editor, cooked asset in build game)
#if USE_EDITOR
-
BytesContainer data;
- if (File::ReadAllBytes(GetPath(), data))
+ if (File::ReadAllBytes(_path, data))
{
LOG(Warning, "Filed to load json asset data. {0}", ToString());
return LoadResult::CannotLoadData;
@@ -104,11 +112,9 @@ Asset::LoadResult JsonAssetBase::loadAsset()
{
return LoadResult::MissingDataChunk;
}
-
#else
-
// Get the asset storage container but don't load it now
- const auto storage = ContentStorageManager::GetStorage(GetPath(), true);
+ const auto storage = ContentStorageManager::GetStorage(_path, true);
if (!storage)
return LoadResult::CannotLoadStorage;
@@ -124,7 +130,6 @@ Asset::LoadResult JsonAssetBase::loadAsset()
if (storage->LoadAssetChunk(chunk))
return LoadResult::CannotLoadData;
auto& data = chunk->Data;
-
#endif
// Parse json document
@@ -176,7 +181,7 @@ void JsonAssetBase::onRename(const StringView& newPath)
#endif
-REGISTER_JSON_ASSET(JsonAsset, "FlaxEngine.JsonAsset");
+REGISTER_JSON_ASSET(JsonAsset, "FlaxEngine.JsonAsset", true);
JsonAsset::JsonAsset(const SpawnParams& params, const AssetInfo* info)
: JsonAssetBase(params, info)
diff --git a/Source/Engine/Content/Loading/ContentLoadTask.h b/Source/Engine/Content/Loading/ContentLoadTask.h
index 94e8d5ec7..df13c8c43 100644
--- a/Source/Engine/Content/Loading/ContentLoadTask.h
+++ b/Source/Engine/Content/Loading/ContentLoadTask.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Threading/Task.h"
+#include "Engine/Core/Types/String.h"
class Asset;
class LoadingThread;
diff --git a/Source/Engine/Content/Loading/ContentLoadingManager.cpp b/Source/Engine/Content/Loading/ContentLoadingManager.cpp
index 6e6ff7a65..5f75e8cd1 100644
--- a/Source/Engine/Content/Loading/ContentLoadingManager.cpp
+++ b/Source/Engine/Content/Loading/ContentLoadingManager.cpp
@@ -165,7 +165,7 @@ bool ContentLoadingManagerService::Init()
// Calculate amount of loading threads to use
const CPUInfo cpuInfo = Platform::GetCPUInfo();
- const int32 count = static_cast(Math::Clamp(LOADING_THREAD_PER_PHYSICAL_CORE * cpuInfo.ProcessorCoreCount, 1.0f, 4.0f));
+ const int32 count = Math::Clamp(static_cast(LOADING_THREAD_PER_PHYSICAL_CORE * (float)cpuInfo.ProcessorCoreCount), 1, 6);
LOG(Info, "Creating {0} content loading threads...", count);
// Create loading threads
diff --git a/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h b/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h
index 5d552b996..752fa7bc4 100644
--- a/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h
+++ b/Source/Engine/Content/Loading/Tasks/LoadAssetDataTask.h
@@ -53,6 +53,9 @@ protected:
AssetReference ref = _asset.Get();
if (ref == nullptr)
return Result::MissingReferences;
+#if TRACY_ENABLE
+ const StringView name(ref->GetPath());
+#endif
// Load chunks
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
@@ -62,11 +65,14 @@ protected:
const auto chunk = ref->GetChunk(i);
if (chunk != nullptr)
{
- // Check for cancel
if (IsCancelRequested())
return Result::Ok;
// Load it
+#if TRACY_ENABLE
+ ZoneScoped;
+ ZoneName(*name, name.Length());
+#endif
if (ref->Storage->LoadAssetChunk(chunk))
{
LOG(Warning, "Cannot load asset \'{0}\' chunk {1}.", ref->ToString(), i);
diff --git a/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h b/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h
index 7a7ea285f..ae8dab9e6 100644
--- a/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h
+++ b/Source/Engine/Content/Loading/Tasks/LoadAssetTask.h
@@ -13,10 +13,6 @@
///
class LoadAssetTask : public ContentLoadTask
{
-private:
-
- WeakAssetReference _asset;
-
public:
///
@@ -25,27 +21,20 @@ public:
/// The asset to load.
LoadAssetTask(Asset* asset)
: ContentLoadTask(Type::LoadAsset)
- , _asset(asset)
+ , Asset(asset)
{
}
public:
- ///
- /// Gets the asset.
- ///
- /// The asset.
- FORCE_INLINE Asset* GetAsset() const
- {
- return _asset.Get();
- }
+ WeakAssetReference Asset;
public:
// [ContentLoadTask]
bool HasReference(Object* obj) const override
{
- return obj == _asset;
+ return obj == Asset;
}
protected:
@@ -55,7 +44,8 @@ protected:
{
PROFILE_CPU();
- AssetReference ref = _asset.Get();
+ // Keep valid ref to the asset
+ AssetReference<::Asset> ref = Asset.Get();
if (ref == nullptr)
return Result::MissingReferences;
@@ -68,7 +58,7 @@ protected:
void OnEnd() override
{
- _asset = nullptr;
+ Asset = nullptr;
// Base
ContentLoadTask::OnEnd();
diff --git a/Source/Engine/Content/Storage/AssetHeader.h b/Source/Engine/Content/Storage/AssetHeader.h
index 19609fd2c..03d8c6028 100644
--- a/Source/Engine/Content/Storage/AssetHeader.h
+++ b/Source/Engine/Content/Storage/AssetHeader.h
@@ -5,7 +5,9 @@
#include "Engine/Core/Types/Guid.h"
#include "Engine/Core/Types/Pair.h"
#include "Engine/Core/Types/String.h"
-#include "Engine/Core/Types/DataContainer.h"
+#if USE_EDITOR
+#include "Engine/Core/Collections/Array.h"
+#endif
#include "FlaxChunk.h"
///
@@ -54,7 +56,8 @@ public:
/// Gets the chunks.
///
/// The output data.
- void GetChunks(Array& output) const
+ template
+ void GetChunks(Array& output) const
{
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
{
@@ -67,7 +70,8 @@ public:
/// Gets the chunks that are loaded.
///
/// The output data.
- void GetLoadedChunks(Array& output) const
+ template
+ void GetLoadedChunks(Array& output) const
{
for (int32 i = 0; i < ASSET_FILE_DATA_CHUNKS; i++)
{
@@ -130,7 +134,7 @@ struct FLAXENGINE_API AssetInitData
///
/// The serialized asset version
///
- uint32 SerializedVersion;
+ uint32 SerializedVersion = 0;
///
/// The custom asset data (should be small, for eg. texture description structure).
@@ -138,7 +142,6 @@ struct FLAXENGINE_API AssetInitData
BytesContainer CustomData;
#if USE_EDITOR
-
///
/// The asset metadata information. Stored in a Json format.
///
@@ -148,24 +151,16 @@ struct FLAXENGINE_API AssetInitData
/// Asset dependencies list used by the asset for tracking (eg. material functions used by material asset). The pair of asset ID and cached file edit time (for tracking modification).
///
Array> Dependencies;
-
#endif
public:
- AssetInitData()
- : SerializedVersion(0)
- {
- }
-
///
/// Gets the hash code.
///
- /// Hash Code
uint32 GetHashCode() const
{
// Note: do not use Metadata/Dependencies because it may not be loaded (it's optional)
-
uint32 hashCode = GetHash(Header.ID);
hashCode = (hashCode * 397) ^ SerializedVersion;
hashCode = (hashCode * 397) ^ CustomData.Length();
diff --git a/Source/Engine/Content/Storage/ContentStorageManager.h b/Source/Engine/Content/Storage/ContentStorageManager.h
index 2d7ce5fd7..e18ead571 100644
--- a/Source/Engine/Content/Storage/ContentStorageManager.h
+++ b/Source/Engine/Content/Storage/ContentStorageManager.h
@@ -3,6 +3,7 @@
#pragma once
#include "FlaxStorageReference.h"
+#include "Engine/Core/Types/TimeSpan.h"
class FlaxFile;
class FlaxPackage;
diff --git a/Source/Engine/Content/Storage/FlaxStorage.cpp b/Source/Engine/Content/Storage/FlaxStorage.cpp
index 1a3d5c6b0..50ed82595 100644
--- a/Source/Engine/Content/Storage/FlaxStorage.cpp
+++ b/Source/Engine/Content/Storage/FlaxStorage.cpp
@@ -5,10 +5,16 @@
#include "FlaxPackage.h"
#include "ContentStorageManager.h"
#include "Engine/Core/Log.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Platform/File.h"
+#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Serialization/FileWriteStream.h"
+#if USE_EDITOR
#include "Engine/Serialization/JsonWriter.h"
#include "Engine/Serialization/JsonWriters.h"
+#else
+#include "Engine/Engine/Globals.h"
+#endif
#include
String AssetHeader::ToString() const
@@ -623,6 +629,7 @@ bool FlaxStorage::LoadAssetChunk(FlaxChunk* chunk)
stream->ReadBytes(tmpBuf.Get(), size);
// Decompress data
+ PROFILE_CPU_NAMED("DecompressLZ4");
chunk->Data.Allocate(originalSize);
const int32 res = LZ4_decompress_safe((const char*)tmpBuf.Get(), chunk->Data.Get(), size, originalSize);
if (res <= 0)
@@ -823,6 +830,7 @@ bool FlaxStorage::Create(WriteStream* stream, const AssetInitData* data, int32 d
const FlaxChunk* chunk = chunks[i];
if (chunk->Flags & FlaxChunkFlags::CompressedLZ4)
{
+ PROFILE_CPU_NAMED("CompressLZ4");
const int32 srcSize = chunk->Data.Length();
const int32 maxSize = LZ4_compressBound(srcSize);
auto& chunkCompressed = compressedChunks[i];
diff --git a/Source/Engine/Content/Storage/FlaxStorageReference.h b/Source/Engine/Content/Storage/FlaxStorageReference.h
index d690227ae..7297bc779 100644
--- a/Source/Engine/Content/Storage/FlaxStorageReference.h
+++ b/Source/Engine/Content/Storage/FlaxStorageReference.h
@@ -5,7 +5,7 @@
#include "FlaxStorage.h"
///
-/// Flax Storage Container Reference
+/// Flax Storage container reference.
///
struct FLAXENGINE_API FlaxStorageReference
{
@@ -44,10 +44,8 @@ public:
public:
- // Assignment operator
FlaxStorageReference& operator=(const FlaxStorageReference& other)
{
- // Protect against invalid self-assignment
if (this != &other)
{
if (_storage)
@@ -56,7 +54,6 @@ public:
if (_storage)
_storage->AddRef();
}
-
return *this;
}
diff --git a/Source/Engine/Content/Storage/JsonStorageProxy.cpp b/Source/Engine/Content/Storage/JsonStorageProxy.cpp
index 8b2f07944..1d5dbdf19 100644
--- a/Source/Engine/Content/Storage/JsonStorageProxy.cpp
+++ b/Source/Engine/Content/Storage/JsonStorageProxy.cpp
@@ -31,7 +31,7 @@ bool JsonStorageProxy::GetAssetInfo(const StringView& path, Guid& resultId, Stri
document.Parse((const char*)fileData.Get(), fileData.Count());
if (document.HasParseError())
{
- Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), String(path));
+ Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), path);
return false;
}
@@ -94,7 +94,7 @@ bool JsonStorageProxy::ChangeId(const StringView& path, const Guid& newId)
document.Parse((const char*)fileData.Get(), fileData.Count());
if (document.HasParseError())
{
- Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), String(path));
+ Log::JsonParseException(document.GetParseError(), document.GetErrorOffset(), path);
return false;
}
diff --git a/Source/Engine/Content/Upgraders/AudioClipUpgrader.h b/Source/Engine/Content/Upgraders/AudioClipUpgrader.h
index 5e2555958..ee0d131b7 100644
--- a/Source/Engine/Content/Upgraders/AudioClipUpgrader.h
+++ b/Source/Engine/Content/Upgraders/AudioClipUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Audio/AudioClip.h"
#include "Engine/Tools/AudioTool/OggVorbisDecoder.h"
@@ -130,3 +132,5 @@ private:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/BinaryAssetUpgrader.h b/Source/Engine/Content/Upgraders/BinaryAssetUpgrader.h
index 2c2d0f03e..551c4e1e7 100644
--- a/Source/Engine/Content/Upgraders/BinaryAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/BinaryAssetUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "IAssetUpgrader.h"
#include "Engine/Content/Storage/AssetHeader.h"
#include "Engine/Core/Log.h"
@@ -9,7 +11,7 @@
///
/// Binary asset upgrading context structure.
///
-struct AssetMigrationContext
+struct FLAXENGINE_API AssetMigrationContext
{
///
/// The input data.
@@ -63,7 +65,7 @@ typedef bool (*UpgradeHandler)(AssetMigrationContext& context);
/// Binary Assets Upgrader base class
///
///
-class BinaryAssetUpgrader : public IAssetUpgrader
+class FLAXENGINE_API BinaryAssetUpgrader : public IAssetUpgrader
{
public:
@@ -205,3 +207,5 @@ public:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/FontAssetUpgrader.h b/Source/Engine/Content/Upgraders/FontAssetUpgrader.h
index cb26fa8d2..8be02b973 100644
--- a/Source/Engine/Content/Upgraders/FontAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/FontAssetUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Render2D/FontAsset.h"
@@ -71,3 +73,5 @@ private:
return CopyChunk(context, 0);
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/IAssetUpgrader.h b/Source/Engine/Content/Upgraders/IAssetUpgrader.h
index f54616a45..edff613e7 100644
--- a/Source/Engine/Content/Upgraders/IAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/IAssetUpgrader.h
@@ -2,12 +2,14 @@
#pragma once
+#if USE_EDITOR
+
#include "Engine/Core/Types/BaseTypes.h"
///
/// The assets upgrading objects interface.
///
-class IAssetUpgrader
+class FLAXENGINE_API IAssetUpgrader
{
public:
@@ -27,3 +29,5 @@ public:
/// True if perform conversion, otherwise false.
virtual bool ShouldUpgrade(uint32 serializedVersion) const = 0;
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/MaterialInstanceUpgrader.h b/Source/Engine/Content/Upgraders/MaterialInstanceUpgrader.h
index 31caeb230..6fd5093f5 100644
--- a/Source/Engine/Content/Upgraders/MaterialInstanceUpgrader.h
+++ b/Source/Engine/Content/Upgraders/MaterialInstanceUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Core/Core.h"
#include "Engine/Platform/Platform.h"
@@ -105,3 +107,5 @@ private:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/ModelAssetUpgrader.h b/Source/Engine/Content/Upgraders/ModelAssetUpgrader.h
index 17b2bda38..b09d1c280 100644
--- a/Source/Engine/Content/Upgraders/ModelAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/ModelAssetUpgrader.h
@@ -2,12 +2,15 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Core/Core.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Serialization/MemoryWriteStream.h"
#include "Engine/Graphics/Models/ModelData.h"
+#include "Engine/Content/Asset.h"
///
/// Model Asset Upgrader
@@ -1222,3 +1225,5 @@ private:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/ShaderAssetUpgrader.h b/Source/Engine/Content/Upgraders/ShaderAssetUpgrader.h
index 827197009..eb84649ad 100644
--- a/Source/Engine/Content/Upgraders/ShaderAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/ShaderAssetUpgrader.h
@@ -2,8 +2,11 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Platform/Platform.h"
+#include "Engine/Graphics/Shaders/Cache/ShaderStorage.h"
///
/// Material Asset and Shader Asset Upgrader
@@ -85,3 +88,5 @@ private:
return CopyChunks(context);
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/SkeletonMaskUpgrader.h b/Source/Engine/Content/Upgraders/SkeletonMaskUpgrader.h
index 5058aed68..431c71014 100644
--- a/Source/Engine/Content/Upgraders/SkeletonMaskUpgrader.h
+++ b/Source/Engine/Content/Upgraders/SkeletonMaskUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Serialization/MemoryReadStream.h"
@@ -97,3 +99,5 @@ private:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h b/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h
index 9a5b4c5ae..c026daebe 100644
--- a/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/SkinnedModelAssetUpgrader.h
@@ -2,10 +2,17 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Platform/Platform.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/Serialization/MemoryWriteStream.h"
+#include "Engine/Graphics/Models/Types.h"
+#include "Engine/Core/Math/BoundingBox.h"
+#include "Engine/Core/Math/BoundingSphere.h"
+#include "Engine/Core/Math/Matrix.h"
+#include "Engine/Core/Math/Transform.h"
///
/// Skinned Model Asset Upgrader
@@ -418,3 +425,5 @@ private:
return false;
}
};
+
+#endif
diff --git a/Source/Engine/Content/Upgraders/TextureAssetUpgrader.h b/Source/Engine/Content/Upgraders/TextureAssetUpgrader.h
index e1d75dba5..a598538f9 100644
--- a/Source/Engine/Content/Upgraders/TextureAssetUpgrader.h
+++ b/Source/Engine/Content/Upgraders/TextureAssetUpgrader.h
@@ -2,6 +2,8 @@
#pragma once
+#if USE_EDITOR
+
#include "BinaryAssetUpgrader.h"
#include "Engine/Core/Core.h"
#include "Engine/Platform/Platform.h"
@@ -825,3 +827,5 @@ private:
return true;
}
};
+
+#endif
diff --git a/Source/Engine/Content/WeakAssetReference.h b/Source/Engine/Content/WeakAssetReference.h
index 4943fd0b5..49401bf25 100644
--- a/Source/Engine/Content/WeakAssetReference.h
+++ b/Source/Engine/Content/WeakAssetReference.h
@@ -229,3 +229,9 @@ public:
OnSet(asset);
}
};
+
+template
+uint32 GetHash(const WeakAssetReference& key)
+{
+ return GetHash(key.GetID());
+}
diff --git a/Source/Engine/ContentImporters/AssetsImportingManager.cpp b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
index f1d048ca5..b4f002b42 100644
--- a/Source/Engine/ContentImporters/AssetsImportingManager.cpp
+++ b/Source/Engine/ContentImporters/AssetsImportingManager.cpp
@@ -31,6 +31,7 @@
#include "CreateParticleEmitterFunction.h"
#include "CreateAnimationGraphFunction.h"
#include "CreateVisualScript.h"
+#include "CreateJson.h"
// Tags used to detect asset creation mode
const String AssetsImportingManager::CreateTextureTag(TEXT("Texture"));
@@ -91,6 +92,10 @@ CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
if (result != CreateAssetResult::Ok)
return result;
+ // Skip for non-flax assets (eg. json resource or custom asset type)
+ if (!TargetAssetPath.EndsWith(ASSET_FILES_EXTENSION))
+ return CreateAssetResult::Ok;
+
// Validate assigned TypeID
if (Data.Header.TypeName.IsEmpty())
{
@@ -112,8 +117,7 @@ CreateAssetResult CreateAssetContext::Run(const CreateAssetFunction& callback)
}
// Save file
- result = Save();
-
+ result = FlaxStorage::Create(OutputPath, Data) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
if (result == CreateAssetResult::Ok)
{
_applyChangesResult = CreateAssetResult::Abort;
@@ -161,11 +165,6 @@ void CreateAssetContext::AddMeta(JsonWriter& writer) const
writer.String(Platform::GetUserName());
}
-CreateAssetResult CreateAssetContext::Save()
-{
- return FlaxStorage::Create(OutputPath, Data) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
-}
-
void CreateAssetContext::ApplyChanges()
{
// Get access
@@ -231,8 +230,6 @@ bool AssetsImportingManager::Create(const String& tag, const StringView& outputP
bool AssetsImportingManager::Import(const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
{
- ASSERT(outputPath.EndsWith(StringView(ASSET_FILES_EXTENSION)));
-
LOG(Info, "Importing file '{0}' to '{1}'...", inputPath, outputPath);
// Check if input file exists
@@ -246,8 +243,7 @@ bool AssetsImportingManager::Import(const StringView& inputPath, const StringVie
const String extension = FileSystem::GetExtension(inputPath).ToLower();
// Special case for raw assets
- const String assetExtension = ASSET_FILES_EXTENSION;
- if (assetExtension.Compare(extension, StringSearchCase::IgnoreCase) == 0)
+ if (StringView(ASSET_FILES_EXTENSION).Compare(StringView(extension), StringSearchCase::IgnoreCase) == 0)
{
// Simply copy file (content layer will resolve duplicated IDs, etc.)
return FileSystem::CopyFile(outputPath, inputPath);
@@ -266,8 +262,6 @@ bool AssetsImportingManager::Import(const StringView& inputPath, const StringVie
bool AssetsImportingManager::ImportIfEdited(const StringView& inputPath, const StringView& outputPath, Guid& assetId, void* arg)
{
- ASSERT(outputPath.EndsWith(StringView(ASSET_FILES_EXTENSION)));
-
// Check if asset not exists
if (!FileSystem::FileExists(outputPath))
{
@@ -338,7 +332,7 @@ bool AssetsImportingManager::Create(const FunctionReload();
}
+ else
+ {
+ Content::GetRegistry()->RegisterAsset(id, String(dataTypename), path);
+ }
return false;
}
+void FormatPoValue(String& value)
+{
+ value.Replace(TEXT("\\n"), TEXT("\n"));
+ value.Replace(TEXT("%s"), TEXT("{}"));
+ value.Replace(TEXT("%d"), TEXT("{}"));
+}
+
+CreateAssetResult CreateJson::ImportPo(CreateAssetContext& context)
+{
+ // Base
+ IMPORT_SETUP(LocalizedStringTable, 1);
+
+ // Load file (UTF-16)
+ String inputData;
+ if (File::ReadAllText(context.InputPath, inputData))
+ {
+ return CreateAssetResult::InvalidPath;
+ }
+
+ // Use virtual asset for data storage and serialization
+ AssetReference asset = Content::CreateVirtualAsset();
+ if (!asset)
+ return CreateAssetResult::Error;
+
+ // Parse PO format
+ int32 pos = 0;
+ int32 pluralCount = 0;
+ int32 lineNumber = 0;
+ bool fuzzy = false, hasNewContext = false;
+ StringView msgctxt, msgid;
+ String idTmp;
+ while (pos < inputData.Length())
+ {
+ // Read line
+ const int32 startPos = pos;
+ while (pos < inputData.Length() && inputData[pos] != '\n')
+ pos++;
+ const StringView line(&inputData[startPos], pos - startPos);
+ lineNumber++;
+ pos++;
+ const int32 valueStart = line.Find('\"') + 1;
+ const int32 valueEnd = line.FindLast('\"');
+ const StringView value(line.Get() + valueStart, Math::Max(valueEnd - valueStart, 0));
+
+ if (line.StartsWith(StringView(TEXT("msgid_plural"))))
+ {
+ // Plural form
+ }
+ else if (line.StartsWith(StringView(TEXT("msgid"))))
+ {
+ // Id
+ msgid = value;
+
+ // Reset context if already used
+ if (!hasNewContext)
+ msgctxt = StringView();
+ hasNewContext = false;
+ }
+ else if (line.StartsWith(StringView(TEXT("msgstr"))))
+ {
+ // String
+ if (msgid.HasChars())
+ {
+ // Format message
+ String msgstr(value);
+ FormatPoValue(msgstr);
+
+ // Get message id
+ StringView id = msgid;
+ if (msgctxt.HasChars())
+ {
+ idTmp = String(msgctxt) + TEXT(".") + String(msgid);
+ id = idTmp;
+ }
+
+ int32 indexStart = line.Find('[');
+ if (indexStart != -1 && indexStart < valueStart)
+ {
+ indexStart++;
+ while (indexStart < line.Length() && StringUtils::IsWhitespace(line[indexStart]))
+ indexStart++;
+ int32 indexEnd = line.Find(']');
+ while (indexEnd > indexStart && StringUtils::IsWhitespace(line[indexEnd - 1]))
+ indexEnd--;
+ int32 index = -1;
+ StringUtils::Parse(line.Get() + indexStart, (uint32)(indexEnd - indexStart), &index);
+ if (pluralCount <= 0)
+ {
+ LOG(Error, "Missing 'nplurals'. Cannot use plural message at line {0}", lineNumber);
+ return CreateAssetResult::Error;
+ }
+ if (index < 0 || index > pluralCount)
+ {
+ LOG(Error, "Invalid plural message index at line {0}", lineNumber);
+ return CreateAssetResult::Error;
+ }
+
+ // Plural message
+ asset->AddPluralString(id, msgstr, index);
+ }
+ else
+ {
+ // Message
+ asset->AddString(id, msgstr);
+ }
+ }
+ }
+ else if (line.StartsWith(StringView(TEXT("msgctxt"))))
+ {
+ // Context
+ msgctxt = value;
+ hasNewContext = true;
+ }
+ else if (line.StartsWith('\"'))
+ {
+ // Config
+ const Char* pluralForms = StringUtils::Find(line.Get(), TEXT("Plural-Forms"));
+ if (pluralForms != nullptr && pluralForms < line.Get() + line.Length() - 1)
+ {
+ // Process plural forms rule
+ const Char* nplurals = StringUtils::Find(pluralForms, TEXT("nplurals"));
+ if (nplurals && nplurals < line.Get() + line.Length())
+ {
+ while (*nplurals && *nplurals != '=')
+ nplurals++;
+ while (*nplurals && (StringUtils::IsWhitespace(*nplurals) || *nplurals == '='))
+ nplurals++;
+ const Char* npluralsStart = nplurals;
+ while (*nplurals && !StringUtils::IsWhitespace(*nplurals) && *nplurals != ';')
+ nplurals++;
+ StringUtils::Parse(npluralsStart, (uint32)(nplurals - npluralsStart), &pluralCount);
+ if (pluralCount < 0 || pluralCount > 100)
+ {
+ LOG(Error, "Invalid 'nplurals' at line {0}", lineNumber);
+ return CreateAssetResult::Error;
+ }
+ }
+ // TODO: parse plural forms rule
+ }
+ const Char* language = StringUtils::Find(line.Get(), TEXT("Language"));
+ if (language != nullptr && language < line.Get() + line.Length() - 1)
+ {
+ // Process language locale
+ while (*language && *language != ':')
+ language++;
+ language++;
+ while (*language && StringUtils::IsWhitespace(*language))
+ language++;
+ const Char* languageStart = language;
+ while (*language && !StringUtils::IsWhitespace(*language) && *language != '\\' && *language != '\"')
+ language++;
+ asset->Locale.Set(languageStart, (int32)(language - languageStart));
+ if (asset->Locale == TEXT("English"))
+ asset->Locale = TEXT("en");
+ if (asset->Locale.Length() > 5)
+ LOG(Warning, "Imported .po file uses invalid locale '{0}'", asset->Locale);
+ }
+ }
+ else if (line.StartsWith('#') || line.IsEmpty())
+ {
+ // Comment
+ const Char* fuzzyPos = StringUtils::Find(line.Get(), TEXT("fuzzy"));
+ fuzzy |= fuzzyPos != nullptr && fuzzyPos < line.Get() + line.Length() - 1;
+ }
+ }
+ if (asset->Locale.IsEmpty())
+ LOG(Warning, "Imported .po file has missing locale");
+
+ // Save asset
+ return asset->Save(context.TargetAssetPath) ? CreateAssetResult::CannotSaveFile : CreateAssetResult::Ok;
+}
+
#endif
diff --git a/Source/Engine/ContentImporters/CreateJson.h b/Source/Engine/ContentImporters/CreateJson.h
index ccc15a792..38ca4b187 100644
--- a/Source/Engine/ContentImporters/CreateJson.h
+++ b/Source/Engine/ContentImporters/CreateJson.h
@@ -18,6 +18,7 @@ public:
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const String& dataTypename);
static bool Create(const StringView& path, rapidjson_flax::StringBuffer& data, const char* dataTypename);
static bool Create(const StringView& path, StringAnsiView& data, StringAnsiView& dataTypename);
+ static CreateAssetResult ImportPo(CreateAssetContext& context);
};
#endif
diff --git a/Source/Engine/ContentImporters/ImportModelFile.cpp b/Source/Engine/ContentImporters/ImportModelFile.cpp
index 073f3edbd..32fd38e4d 100644
--- a/Source/Engine/ContentImporters/ImportModelFile.cpp
+++ b/Source/Engine/ContentImporters/ImportModelFile.cpp
@@ -115,7 +115,8 @@ CreateAssetResult ImportModelFile::Import(CreateAssetContext& context)
// Import model file
ModelData modelData;
String errorMsg;
- if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, StringUtils::GetDirectoryName(context.TargetAssetPath) / StringUtils::GetFileNameWithoutExtension(context.InputPath)))
+ String autoImportOutput = String(StringUtils::GetDirectoryName(context.TargetAssetPath)) / StringUtils::GetFileNameWithoutExtension(context.InputPath);
+ if (ModelTool::ImportModel(context.InputPath, modelData, options, errorMsg, autoImportOutput))
{
LOG(Error, "Cannot import model file. {0}", errorMsg);
return CreateAssetResult::Error;
diff --git a/Source/Engine/ContentImporters/Types.h b/Source/Engine/ContentImporters/Types.h
index 051b865d8..92aa7f533 100644
--- a/Source/Engine/ContentImporters/Types.h
+++ b/Source/Engine/ContentImporters/Types.h
@@ -111,12 +111,6 @@ public:
/// The json metadata writer.
void AddMeta(JsonWriter& writer) const;
- ///
- /// Save asset file data to the hard drive
- ///
- /// Saving result
- CreateAssetResult Save();
-
private:
void ApplyChanges();
@@ -130,12 +124,17 @@ struct AssetImporter
public:
///
- /// Extension of the file to import with that importer
+ /// Extension of the file to import with that importer (without leading dot).
///
String FileExtension;
///
- /// Call asset importing process
+ /// Extension of the output file as output with that importer (without leading dot).
+ ///
+ String ResultExtension;
+
+ ///
+ /// Callback for the asset importing process.
///
CreateAssetFunction Callback;
};
diff --git a/Source/Engine/Core/Collections/Array.h b/Source/Engine/Core/Collections/Array.h
index 3819323a9..9b8c41245 100644
--- a/Source/Engine/Core/Collections/Array.h
+++ b/Source/Engine/Core/Collections/Array.h
@@ -758,7 +758,6 @@ public:
///
/// Performs pop from stack operation (stack grows at the end of the collection).
///
- /// The item.
T Pop()
{
T item(Last());
@@ -769,19 +768,19 @@ public:
///
/// Peeks items which is at the top of the stack (stack grows at the end of the collection).
///
- /// The item.
FORCE_INLINE T& Peek()
{
- return Last();
+ ASSERT(_count > 0);
+ return Get()[_count - 1];
}
///
/// Peeks items which is at the top of the stack (stack grows at the end of the collection).
///
- /// The item.
FORCE_INLINE const T& Peek() const
{
- return Last();
+ ASSERT(_count > 0);
+ return Get()[_count - 1];
}
public:
diff --git a/Source/Engine/Core/Collections/Dictionary.h b/Source/Engine/Core/Collections/Dictionary.h
index 99bad0bef..08b404bfd 100644
--- a/Source/Engine/Core/Collections/Dictionary.h
+++ b/Source/Engine/Core/Collections/Dictionary.h
@@ -2,7 +2,7 @@
#pragma once
-#include "Engine/Core/Collections/Array.h"
+#include "Engine/Core/Memory/Memory.h"
#include "Engine/Core/Collections/HashFunctions.h"
#include "Engine/Core/Collections/Config.h"
@@ -781,7 +781,8 @@ public:
/// Gets the keys collection to the output array (will contain unique items).
///
/// The result.
- void GetKeys(Array& result) const
+ template
+ void GetKeys(Array& result) const
{
for (auto i = Begin(); i.IsNotEnd(); ++i)
result.Add(i->Key);
@@ -791,7 +792,8 @@ public:
/// Gets the values collection to the output array (may contain duplicates).
///
/// The result.
- void GetValues(Array& result) const
+ template
+ void GetValues(Array& result) const
{
for (auto i = Begin(); i.IsNotEnd(); ++i)
result.Add(i->Value);
diff --git a/Source/Engine/Core/Config/GameSettings.cpp b/Source/Engine/Core/Config/GameSettings.cpp
index e2789c0e2..5b333b227 100644
--- a/Source/Engine/Core/Config/GameSettings.cpp
+++ b/Source/Engine/Core/Config/GameSettings.cpp
@@ -13,6 +13,7 @@
#include "Engine/Input/InputSettings.h"
#include "Engine/Audio/AudioSettings.h"
#include "Engine/Navigation/NavigationSettings.h"
+#include "Engine/Localization/LocalizationSettings.h"
#include "Engine/Content/Content.h"
#include "Engine/Content/JsonAsset.h"
#include "Engine/Content/AssetReference.h"
@@ -127,6 +128,7 @@ bool GameSettings::Load()
PRELOAD_SETTINGS(Input);
PRELOAD_SETTINGS(Graphics);
PRELOAD_SETTINGS(Navigation);
+ PRELOAD_SETTINGS(Localization);
PRELOAD_SETTINGS(GameCooking);
#undef PRELOAD_SETTINGS
@@ -158,6 +160,7 @@ void GameSettings::Apply()
APPLY_SETTINGS(InputSettings);
APPLY_SETTINGS(GraphicsSettings);
APPLY_SETTINGS(NavigationSettings);
+ APPLY_SETTINGS(LocalizationSettings);
APPLY_SETTINGS(BuildSettings);
APPLY_SETTINGS(PlatformSettings);
#undef APPLY_SETTINGS
@@ -197,6 +200,7 @@ void GameSettings::Deserialize(DeserializeStream& stream, ISerializeModifier* mo
DESERIALIZE(Input);
DESERIALIZE(Graphics);
DESERIALIZE(Navigation);
+ DESERIALIZE(Localization);
DESERIALIZE(GameCooking);
// Per-platform settings containers
diff --git a/Source/Engine/Core/Config/GameSettings.cs b/Source/Engine/Core/Config/GameSettings.cs
index 0767d795a..ed96ef4e6 100644
--- a/Source/Engine/Core/Config/GameSettings.cs
+++ b/Source/Engine/Core/Config/GameSettings.cs
@@ -79,6 +79,12 @@ namespace FlaxEditor.Content.Settings
[EditorOrder(1045), EditorDisplay("Other Settings"), AssetReference(typeof(NavigationSettings), true), Tooltip("Reference to Navigation Settings asset")]
public JsonAsset Navigation;
+ ///
+ /// Reference to asset.
+ ///
+ [EditorOrder(1046), EditorDisplay("Other Settings"), AssetReference(typeof(LocalizationSettings), true), Tooltip("Reference to Localization Settings asset")]
+ public JsonAsset Localization;
+
///
/// Reference to asset.
///
@@ -219,6 +225,8 @@ namespace FlaxEditor.Content.Settings
return LoadAsset(gameSettings.Graphics) as T;
if (type == typeof(NavigationSettings))
return LoadAsset(gameSettings.Navigation) as T;
+ if (type == typeof(LocalizationSettings))
+ return LoadAsset(gameSettings.Localization) as T;
if (type == typeof(BuildSettings))
return LoadAsset(gameSettings.GameCooking) as T;
if (type == typeof(InputSettings))
@@ -321,6 +329,8 @@ namespace FlaxEditor.Content.Settings
return SaveAsset(gameSettings, ref gameSettings.Graphics, obj);
if (type == typeof(NavigationSettings))
return SaveAsset(gameSettings, ref gameSettings.Navigation, obj);
+ if (type == typeof(LocalizationSettings))
+ return SaveAsset(gameSettings, ref gameSettings.Localization, obj);
if (type == typeof(BuildSettings))
return SaveAsset(gameSettings, ref gameSettings.GameCooking, obj);
if (type == typeof(InputSettings))
diff --git a/Source/Engine/Core/Config/GameSettings.h b/Source/Engine/Core/Config/GameSettings.h
index 63745d9d8..8016bdbe4 100644
--- a/Source/Engine/Core/Config/GameSettings.h
+++ b/Source/Engine/Core/Config/GameSettings.h
@@ -68,6 +68,7 @@ public:
Guid Input;
Guid Graphics;
Guid Navigation;
+ Guid Localization;
Guid GameCooking;
// Per-platform settings containers
diff --git a/Source/Engine/Core/Config/LayersTagsSettings.h b/Source/Engine/Core/Config/LayersTagsSettings.h
index 066b5cdd5..c72ab3974 100644
--- a/Source/Engine/Core/Config/LayersTagsSettings.h
+++ b/Source/Engine/Core/Config/LayersTagsSettings.h
@@ -3,6 +3,8 @@
#pragma once
#include "Engine/Core/Config/Settings.h"
+#include "Engine/Core/Types/String.h"
+#include "Engine/Core/Collections/Array.h"
///
/// Layers and objects tags settings.
diff --git a/Source/Engine/Core/Delegate.h b/Source/Engine/Core/Delegate.h
index d4118c3da..17c0c6afe 100644
--- a/Source/Engine/Core/Delegate.h
+++ b/Source/Engine/Core/Delegate.h
@@ -4,11 +4,6 @@
#include "Engine/Core/Memory/Allocation.h"
-template
-class Function;
-template
-class Delegate;
-
///
/// The function object.
///
diff --git a/Source/Engine/Core/DeleteMe.h b/Source/Engine/Core/DeleteMe.h
index fddb16f7a..7dc366b98 100644
--- a/Source/Engine/Core/DeleteMe.h
+++ b/Source/Engine/Core/DeleteMe.h
@@ -2,6 +2,8 @@
#pragma once
+#include "Engine/Core/Compiler.h"
+
///
/// Helper class used to delete another object.
///
diff --git a/Source/Engine/Core/Math/Math.h b/Source/Engine/Core/Math/Math.h
index ee3b34b9a..e9bd6e58f 100644
--- a/Source/Engine/Core/Math/Math.h
+++ b/Source/Engine/Core/Math/Math.h
@@ -13,6 +13,7 @@
#define PI_OVER_2 1.57079632679f
#define PI_OVER_4 0.78539816339f
#define PI_HALF PI_OVER_2
+#define GOLDEN_RATIO 1.6180339887f
// The value for which all absolute numbers smaller than are considered equal to zero.
#define ZeroTolerance 1e-6f
@@ -648,9 +649,9 @@ namespace Math
{
float delta = a2 - a1;
if (delta > PI)
- delta = delta - PI * 2.0f;
+ delta = delta - TWO_PI;
else if (delta < -PI)
- delta = delta + PI * 2.0f;
+ delta = delta + TWO_PI;
return delta;
}
@@ -658,9 +659,9 @@ namespace Math
static float UnwindRadians(float a)
{
while (a > PI)
- a -= (float)PI * 2.0f;
+ a -= TWO_PI;
while (a < -PI)
- a += (float)PI * 2.0f;
+ a += TWO_PI;
return a;
}
diff --git a/Source/Engine/Core/Math/Rectangle.cs b/Source/Engine/Core/Math/Rectangle.cs
index 50f9adce4..d1fb16abc 100644
--- a/Source/Engine/Core/Math/Rectangle.cs
+++ b/Source/Engine/Core/Math/Rectangle.cs
@@ -285,6 +285,19 @@ namespace FlaxEngine
return new Rectangle(Location - toExpand * 0.5f, Size + toExpand);
}
+ ///
+ /// Calculates a rectangle that includes the margins (inside).
+ ///
+ /// The rectangle.
+ /// The margin to apply to the rectangle.
+ /// Rectangle inside the given rectangle after applying margins inside it.
+ public static Rectangle Margin(Rectangle value, GUI.Margin margin)
+ {
+ value.Location += margin.Location;
+ value.Size -= margin.Size;
+ return value;
+ }
+
///
/// Calculates a rectangle that contains the union of a and b rectangles
///
diff --git a/Source/Engine/Core/Math/Vector3.h b/Source/Engine/Core/Math/Vector3.h
index d9a1d6036..761977c96 100644
--- a/Source/Engine/Core/Math/Vector3.h
+++ b/Source/Engine/Core/Math/Vector3.h
@@ -912,6 +912,7 @@ public:
/// The third triangle vertex.
/// The triangle area.
static float TriangleArea(const Vector3& v0, const Vector3& v1, const Vector3& v2);
+
};
inline Vector3 operator+(float a, const Vector3& b)
diff --git a/Source/Engine/Core/Memory/Memory.h b/Source/Engine/Core/Memory/Memory.h
index 6341ca21f..59d316287 100644
--- a/Source/Engine/Core/Memory/Memory.h
+++ b/Source/Engine/Core/Memory/Memory.h
@@ -3,6 +3,8 @@
#pragma once
#include "Engine/Core/Templates.h"
+#include "Engine/Platform/Platform.h"
+#include
#include "CrtAllocator.h"
typedef CrtAllocator Allocator;
@@ -24,10 +26,7 @@ namespace AllocatorExt
return nullptr;
}
if (!ptr)
- {
return Allocator::Allocate(newSize);
- }
-
void* result = Allocator::Allocate(newSize);
if (result)
{
@@ -53,14 +52,9 @@ namespace AllocatorExt
return nullptr;
}
if (!ptr)
- {
return Allocator::Allocate(newSize);
- }
if (newSize <= oldSize)
- {
return ptr;
- }
-
void* result = Allocator::Allocate(newSize);
if (result)
{
diff --git a/Source/Engine/Core/Types/BaseTypes.h b/Source/Engine/Core/Types/BaseTypes.h
index b57f139ff..90ad934c2 100644
--- a/Source/Engine/Core/Types/BaseTypes.h
+++ b/Source/Engine/Core/Types/BaseTypes.h
@@ -97,6 +97,10 @@ template
class Pair;
template
class Dictionary;
+template
+class Function;
+template
+class Delegate;
// Declares full set of operators for the enum type (using binary operation on integer values)
#define DECLARE_ENUM_OPERATORS(T) \
diff --git a/Source/Engine/Core/Types/DataContainer.h b/Source/Engine/Core/Types/DataContainer.h
index 8b504e58f..5767ca7b9 100644
--- a/Source/Engine/Core/Types/DataContainer.h
+++ b/Source/Engine/Core/Types/DataContainer.h
@@ -3,10 +3,9 @@
#pragma once
#include "Span.h"
-#include "Engine/Core/Collections/Array.h"
+#include "Engine/Core/Templates.h"
+#include "Engine/Core/Memory/Memory.h"
#include "Engine/Platform/Platform.h"
-#include "Engine/Serialization/WriteStream.h"
-#include "Engine/Serialization/ReadStream.h"
///
/// Universal utility class that can store the chunk of data or just reference to the memory.
@@ -49,7 +48,8 @@ public:
/// Initializes a new instance of the class.
///
/// The data array to link.
- DataContainer(const Array& data)
+ template
+ DataContainer(const Array& data)
: Base((T*)data.Get(), data.Count())
, _isAllocated(false)
{
@@ -60,6 +60,7 @@ public:
///
/// Other container to copy
DataContainer(const DataContainer& other)
+ : DataContainer()
{
if (other.IsAllocated())
Copy(other);
@@ -71,12 +72,11 @@ public:
/// Initializes a new instance of the class.
///
/// The other collection to move.
- FORCE_INLINE DataContainer(DataContainer&& other)
+ DataContainer(DataContainer&& other) noexcept
{
Base::_data = other._data;
Base::_length = other._length;
_isAllocated = other._isAllocated;
-
other._data = nullptr;
other._length = 0;
other._isAllocated = false;
@@ -87,16 +87,14 @@ public:
///
/// The other collection to move.
/// The reference to this.
- DataContainer& operator=(DataContainer&& other)
+ DataContainer& operator=(DataContainer&& other) noexcept
{
if (this != &other)
{
Release();
-
Base::_data = other._data;
Base::_length = other._length;
_isAllocated = other._isAllocated;
-
other._data = nullptr;
other._length = 0;
other._isAllocated = false;
@@ -122,7 +120,7 @@ public:
}
///
- /// Destructor
+ /// Releases any allocated memory.
///
~DataContainer()
{
@@ -133,47 +131,45 @@ public:
public:
///
- /// Returns true if data is allocated by container itself
+ /// Returns true if data is allocated by container itself, otherwise it's just linked.
///
- /// True if is allocated by container, otherwise false
FORCE_INLINE bool IsAllocated() const
{
return _isAllocated;
}
-public:
-
///
- /// Link external data
+ /// Links the external data.
///
/// Data array to link
- void Link(const Array& data)
+ template
+ void Link(const Array& data)
{
Link(data.Get(), data.Count());
}
///
- /// Link external data
+ /// Links the external data.
///
- /// Data to link
+ /// Data to link.
FORCE_INLINE void Link(const Span& data)
{
Link(data.Get(), data.Length());
}
///
- /// Link external data
+ /// Links the external data.
///
- /// Data to link
+ /// Data to link.
FORCE_INLINE void Link(const DataContainer& data)
{
Link(data.Get(), data.Length());
}
///
- /// Link external data
+ /// Links external data.
///
- /// Data to link
+ /// Data to link.
template
FORCE_INLINE void Link(const U* data)
{
@@ -181,30 +177,27 @@ public:
}
///
- /// Link external data
+ /// Links the external data.
///
- /// Data pointer
- /// Data length
+ /// Data pointer.
+ /// Data length.
void Link(const T* data, int32 length)
{
Release();
-
_isAllocated = false;
Base::_length = length;
Base::_data = (T*)data;
}
///
- /// Allocate new memory chunk
+ /// Allocate a new memory chunk.
///
- /// Length of the data (amount of T elements)
+ /// Length of the data (amount of T elements).
void Allocate(const int32 length)
{
if (_isAllocated && Base::_length == length)
return;
-
Release();
-
if (length > 0)
{
_isAllocated = true;
@@ -214,10 +207,11 @@ public:
}
///
- /// Copies the data to a new allocated chunk
+ /// Copies the data to a new allocated chunk.
///
- /// Data array to copy
- FORCE_INLINE void Copy(const Array& data)
+ /// Data array to copy.
+ template
+ FORCE_INLINE void Copy(const Array& data)
{
if (data.HasItems())
Copy(data.Get(), data.Count());
@@ -226,10 +220,10 @@ public:
}
///
- /// Copies the data to a new allocated chunk
+ /// Copies the data to a new allocated chunk.
///
- /// Data to copy
- FORCE_INLINE void Copy(const DataContainer& data)
+ /// Data to copy.
+ void Copy(const DataContainer& data)
{
if (data.IsValid())
Copy(data.Get(), data.Length());
@@ -238,10 +232,10 @@ public:
}
///
- /// Copies the data to a new allocated chunk
+ /// Copies the data to a new allocated chunk.
///
- /// Data to copy
- FORCE_INLINE void Copy(const Span& data)
+ /// Data to copy.
+ void Copy(const Span& data)
{
if (data.IsValid())
Copy(data.Get(), data.Length());
@@ -250,9 +244,9 @@ public:
}
///
- /// Copies the data to a new allocated chunk
+ /// Copies the data to a new allocated chunk.
///
- /// Pointer to data to copy
+ /// Pointer to data to copy.
template
FORCE_INLINE void Copy(const U* data)
{
@@ -260,14 +254,13 @@ public:
}
///
- /// Copies the data to a new allocated chunk
+ /// Copies the data to a new allocated chunk.
///
- /// Pointer to data to copy
- /// Length of the data (amount of T elements)
+ /// Pointer to data to copy.
+ /// Length of the data (amount of T elements).
void Copy(const T* data, int32 length)
{
ASSERT(data && length > 0);
-
Allocate(length);
ASSERT(Base::_data);
Platform::MemoryCopy(Base::_data, data, length * sizeof(T));
@@ -347,10 +340,9 @@ public:
public:
+ template
void Read(ReadStream* stream, int32 length)
{
- // Note: this may not work for the objects, use with primitive types and structures
-
ASSERT(stream != nullptr);
Allocate(length);
if (length > 0)
@@ -359,10 +351,9 @@ public:
}
}
+ template
void Write(WriteStream* stream) const
{
- // Note: this may not work for the objects, use with primitive types and structures
-
ASSERT(stream != nullptr);
if (Base::_length > 0)
{
diff --git a/Source/Engine/Core/Types/DateTime.cpp b/Source/Engine/Core/Types/DateTime.cpp
index 5090c62a1..c4d2124ad 100644
--- a/Source/Engine/Core/Types/DateTime.cpp
+++ b/Source/Engine/Core/Types/DateTime.cpp
@@ -6,8 +6,8 @@
#include "Engine/Platform/Platform.h"
#include "Engine/Core/Math/Math.h"
-const int32 DateTime::CachedDaysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-const int32 DateTime::CachedDaysToMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
+const int32 CachedDaysPerMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+const int32 CachedDaysToMonth[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute, int32 second, int32 millisecond)
{
@@ -25,6 +25,11 @@ DateTime::DateTime(int32 year, int32 month, int32 day, int32 hour, int32 minute,
+ millisecond * Constants::TicksPerMillisecond;
}
+DateTime DateTime::GetDate() const
+{
+ return DateTime(Ticks - Ticks % Constants::TicksPerDay);
+}
+
void DateTime::GetDate(int32& year, int32& month, int32& day) const
{
// Based on:
@@ -68,6 +73,11 @@ int32 DateTime::GetDayOfYear() const
return day;
}
+int32 DateTime::GetHour() const
+{
+ return static_cast(Ticks / Constants::TicksPerHour % 24);
+}
+
int32 DateTime::GetHour12() const
{
const int32 hour = GetHour();
@@ -78,6 +88,26 @@ int32 DateTime::GetHour12() const
return hour;
}
+double DateTime::GetJulianDay() const
+{
+ return 1721425.5 + static_cast(Ticks) / Constants::TicksPerDay;
+}
+
+double DateTime::GetModifiedJulianDay() const
+{
+ return GetJulianDay() - 2400000.5;
+}
+
+int32 DateTime::GetMillisecond() const
+{
+ return static_cast(Ticks / Constants::TicksPerMillisecond % 1000);
+}
+
+int32 DateTime::GetMinute() const
+{
+ return static_cast(Ticks / Constants::TicksPerMinute % 60);
+}
+
int32 DateTime::GetMonth() const
{
int32 year, month, day;
@@ -85,6 +115,21 @@ int32 DateTime::GetMonth() const
return month;
}
+MonthOfYear DateTime::GetMonthOfYear() const
+{
+ return static_cast(GetMonth());
+}
+
+int32 DateTime::GetSecond() const
+{
+ return static_cast(Ticks / Constants::TicksPerSecond % 60);
+}
+
+TimeSpan DateTime::GetTimeOfDay() const
+{
+ return TimeSpan(Ticks % Constants::TicksPerDay);
+}
+
int32 DateTime::GetYear() const
{
int32 year, month, day;
@@ -92,6 +137,11 @@ int32 DateTime::GetYear() const
return year;
}
+int32 DateTime::ToUnixTimestamp() const
+{
+ return static_cast((Ticks - DateTime(1970, 1, 1).Ticks) / Constants::TicksPerSecond);
+}
+
int32 DateTime::DaysInMonth(int32 year, int32 month)
{
ASSERT_LOW_LAYER((month >= 1) && (month <= 12));
@@ -105,6 +155,16 @@ int32 DateTime::DaysInYear(int32 year)
return IsLeapYear(year) ? 366 : 365;
}
+DateTime DateTime::FromJulianDay(double julianDay)
+{
+ return DateTime(static_cast((julianDay - 1721425.5) * Constants::TicksPerDay));
+}
+
+DateTime DateTime::FromUnixTimestamp(int32 unixTime)
+{
+ return DateTime(1970, 1, 1) + TimeSpan(static_cast(unixTime) * Constants::TicksPerSecond);
+}
+
bool DateTime::IsLeapYear(int32 year)
{
if ((year % 4) == 0)
@@ -114,6 +174,11 @@ bool DateTime::IsLeapYear(int32 year)
return false;
}
+DateTime DateTime::MaxValue()
+{
+ return DateTime(3652059 * Constants::TicksPerDay - 1);
+}
+
DateTime DateTime::Now()
{
int32 year, month, day, dayOfWeek, hour, minute, second, millisecond;
@@ -144,3 +209,30 @@ String DateTime::ToFileNameString() const
GetDate(year, month, day);
return String::Format(TEXT("{0}_{1:0>2}_{2:0>2}_{3:0>2}_{4:0>2}_{5:0>2}"), year, month, day, GetHour(), GetMinute(), GetSecond());
}
+
+DateTime DateTime::operator+(const TimeSpan& other) const
+{
+ return DateTime(Ticks + other.Ticks);
+}
+
+DateTime& DateTime::operator+=(const TimeSpan& other)
+{
+ Ticks += other.Ticks;
+ return *this;
+}
+
+TimeSpan DateTime::operator-(const DateTime& other) const
+{
+ return TimeSpan(Ticks - other.Ticks);
+}
+
+DateTime DateTime::operator-(const TimeSpan& other) const
+{
+ return DateTime(Ticks - other.Ticks);
+}
+
+DateTime& DateTime::operator-=(const TimeSpan& other)
+{
+ Ticks -= other.Ticks;
+ return *this;
+}
diff --git a/Source/Engine/Core/Types/DateTime.h b/Source/Engine/Core/Types/DateTime.h
index a1bf245e1..08817f78f 100644
--- a/Source/Engine/Core/Types/DateTime.h
+++ b/Source/Engine/Core/Types/DateTime.h
@@ -3,7 +3,8 @@
#pragma once
#include "BaseTypes.h"
-#include "TimeSpan.h"
+#include "Engine/Core/Formatting.h"
+#include "Engine/Core/Templates.h"
#include "Engine/Core/Enums.h"
///
@@ -21,11 +22,6 @@ DECLARE_ENUM_EX_12(MonthOfYear, int32, 1, January, February, March, April, May,
///
API_STRUCT(InBuild, Namespace="System") struct FLAXENGINE_API DateTime
{
-private:
-
- static const int32 CachedDaysPerMonth[];
- static const int32 CachedDaysToMonth[];
-
public:
///
@@ -77,32 +73,11 @@ public:
public:
- DateTime operator+(const TimeSpan& other) const
- {
- return DateTime(Ticks + other.Ticks);
- }
-
- DateTime& operator+=(const TimeSpan& other)
- {
- Ticks += other.Ticks;
- return *this;
- }
-
- TimeSpan operator-(const DateTime& other) const
- {
- return TimeSpan(Ticks - other.Ticks);
- }
-
- DateTime operator-(const TimeSpan& other) const
- {
- return DateTime(Ticks - other.Ticks);
- }
-
- DateTime& operator-=(const TimeSpan& other)
- {
- Ticks -= other.Ticks;
- return *this;
- }
+ DateTime operator+(const TimeSpan& other) const;
+ DateTime& operator+=(const TimeSpan& other);
+ TimeSpan operator-(const DateTime& other) const;
+ DateTime operator-(const TimeSpan& other) const;
+ DateTime& operator-=(const TimeSpan& other);
bool operator==(const DateTime& other) const
{
@@ -139,11 +114,7 @@ public:
///
/// Gets the date part of this date. The time part is truncated and becomes 00:00:00.000.
///
- /// A DateTime object containing the date.
- DateTime GetDate() const
- {
- return DateTime(Ticks - Ticks % Constants::TicksPerDay);
- }
+ DateTime GetDate() const;
///
/// Gets the date components of this date.
@@ -156,106 +127,68 @@ public:
///
/// Gets this date's day part (1 to 31).
///
- /// The day of the month.
int32 GetDay() const;
///
/// Calculates this date's day of the week (Sunday - Saturday).
///
- /// The week day.
DayOfWeek GetDayOfWeek() const;
///
/// Gets this date's day of the year.
///
- /// The day of year.
int32 GetDayOfYear() const;
///
/// Gets this date's hour part in 24-hour clock format (0 to 23).
///
- /// The hour.
- int32 GetHour() const
- {
- return static_cast(Ticks / Constants::TicksPerHour % 24);
- }
+ int32 GetHour() const;
///
/// Gets this date's hour part in 12-hour clock format (1 to 12).
///
- /// The hour in AM/PM format.
int32 GetHour12() const;
///
/// Gets the Julian Day for this date.
///
- ///
- /// The Julian Day is the number of days since the inception of the Julian calendar at noon on Monday, January 1, 4713 B.C.E. The minimum Julian Day that can be represented in DateTime is 1721425.5, which corresponds to Monday, January 1, 0001 in the Gregorian calendar.
- ///
- /// Julian Day.
- double GetJulianDay() const
- {
- return 1721425.5 + static_cast(Ticks) / Constants::TicksPerDay;
- }
+ /// The Julian Day is the number of days since the inception of the Julian calendar at noon on Monday, January 1, 4713 B.C.E. The minimum Julian Day that can be represented in DateTime is 1721425.5, which corresponds to Monday, January 1, 0001 in the Gregorian calendar.
+ double GetJulianDay() const;
///
/// Gets the Modified Julian day.
///
- ///
- /// The Modified Julian Day is calculated by subtracting 2400000.5, which corresponds to midnight UTC on November 17, 1858 in the Gregorian calendar.
- ///
- /// The Modified Julian Day.
- double GetModifiedJulianDay() const
- {
- return GetJulianDay() - 2400000.5;
- }
+ /// The Modified Julian Day is calculated by subtracting 2400000.5, which corresponds to midnight UTC on November 17, 1858 in the Gregorian calendar.
+ double GetModifiedJulianDay() const;
///
/// Gets this date's millisecond part (0 to 999).
///
- /// The millisecond.
- int32 GetMillisecond() const
- {
- return static_cast(Ticks / Constants::TicksPerMillisecond % 1000);
- }
+ int32 GetMillisecond() const;
///
/// Gets this date's minute part (0 to 59).
///
- /// The minute.
- int32 GetMinute() const
- {
- return static_cast(Ticks / Constants::TicksPerMinute % 60);
- }
+ int32 GetMinute() const;
///
/// Gets this date's the month part (1 to 12).
///
- /// The month.
int32 GetMonth() const;
///
/// Gets the date's month of the year (January to December).
///
- /// The month of year.
- MonthOfYear GetMonthOfYear() const
- {
- return static_cast(GetMonth());
- }
+ MonthOfYear GetMonthOfYear() const;
///
/// Gets this date's second part.
///
- /// The second.
- int32 GetSecond() const
- {
- return static_cast(Ticks / Constants::TicksPerSecond % 60);
- }
+ int32 GetSecond() const;
///
- /// Gets this date's representation as number of ticks.
+ /// Gets this date's representation as number of ticks since midnight, January 1, 0001.
///
- /// The number of ticks since midnight, January 1, 0001.
int64 GetTicks() const
{
return Ticks;
@@ -264,26 +197,17 @@ public:
///
/// Gets the time elapsed since midnight of this date.
///
- /// The time span since midnight.
- TimeSpan GetTimeOfDay() const
- {
- return TimeSpan(Ticks % Constants::TicksPerDay);
- }
+ TimeSpan GetTimeOfDay() const;
///
/// Gets this date's year part.
///
- /// The year.
int32 GetYear() const;
///
/// Gets this date as the number of seconds since the Unix Epoch (January 1st of 1970).
///
- /// The time.
- int32 ToUnixTimestamp() const
- {
- return static_cast((Ticks - DateTime(1970, 1, 1).Ticks) / Constants::TicksPerSecond);
- }
+ int32 ToUnixTimestamp() const;
public:
@@ -307,27 +231,19 @@ public:
///
/// The Julian Day.
/// Gregorian date and time.
- static DateTime FromJulianDay(double julianDay)
- {
- return DateTime(static_cast((julianDay - 1721425.5) * Constants::TicksPerDay));
- }
+ static DateTime FromJulianDay(double julianDay);
///
/// Returns the date from Unix time (seconds from midnight 1970-01-01).
///
/// The Unix time (seconds from midnight 1970-01-01).
/// The Gregorian date and time.
- static DateTime FromUnixTimestamp(int32 unixTime)
- {
- return DateTime(1970, 1, 1) + TimeSpan(static_cast(unixTime) * Constants::TicksPerSecond);
- }
+ static DateTime FromUnixTimestamp(int32 unixTime);
///
/// Determines whether the specified year is a leap year.
///
- ///
- /// A leap year is a year containing one additional day in order to keep the calendar synchronized with the astronomical year.
- ///
+ /// A leap year is a year containing one additional day in order to keep the calendar synchronized with the astronomical year.
/// The year.
/// true if the specified year os a leap year; otherwise, false.
static bool IsLeapYear(int32 year);
@@ -335,22 +251,15 @@ public:
///
/// Returns the maximum date value.
///
- ///
- /// The maximum date value is December 31, 9999, 23:59:59.9999999.
- ///
- /// The date.
- static DateTime MaxValue()
- {
- return DateTime(3652059 * Constants::TicksPerDay - 1);
- }
+ /// The maximum date value is December 31, 9999, 23:59:59.9999999.
+ /// The maximum valid date.
+ static DateTime MaxValue();
///
/// Returns the minimum date value.
///
- ///
- /// The minimum date value is January 1, 0001, 00:00:00.0.
- ///
- /// The date.
+ /// The minimum date value is January 1, 0001, 00:00:00.0.
+ /// The minimum valid date.
static DateTime MinValue()
{
return DateTime(1, 1, 1, 0, 0, 0, 0);
@@ -359,18 +268,14 @@ public:
///
/// Gets the local date and time on this computer.
///
- ///
- ///This method takes into account the local computer's time zone and daylight saving settings. For time zone independent time comparisons, and when comparing times between different computers, use NowUTC() instead.
- ///
+ /// This method takes into account the local computer's time zone and daylight saving settings. For time zone independent time comparisons, and when comparing times between different computers, use NowUTC() instead.
/// The current date and time.
static DateTime Now();
///
/// Gets the UTC date and time on this computer.
///
- ///
- /// This method returns the Coordinated Universal Time (UTC), which does not take the local computer's time zone and daylight savings settings into account. It should be used when comparing dates and times that should be independent of the user's locale. To get the date and time in the current locale, use Now() instead.
- ///
+ /// This method returns the Coordinated Universal Time (UTC), which does not take the local computer's time zone and daylight savings settings into account. It should be used when comparing dates and times that should be independent of the user's locale. To get the date and time in the current locale, use Now() instead.
/// The current date and time.
static DateTime NowUTC();
diff --git a/Source/Engine/Core/Types/Guid.cpp b/Source/Engine/Core/Types/Guid.cpp
index 323949646..c8aaf8aa1 100644
--- a/Source/Engine/Core/Types/Guid.cpp
+++ b/Source/Engine/Core/Types/Guid.cpp
@@ -101,8 +101,8 @@ FORCE_INLINE bool GuidParse(const StringViewType& text, Guid& value)
// FormatType::D
case 36:
{
- StringType b = text.Substring(9, 4) + text.Substring(14, 4);
- StringType c = text.Substring(19, 4) + text.Substring(24, 4);
+ StringType b = StringType(text.Substring(9, 4)) + text.Substring(14, 4);
+ StringType c = StringType(text.Substring(19, 4)) + text.Substring(24, 4);
return
StringUtils::ParseHex(*text + 0, 8, &value.A) ||
StringUtils::ParseHex(*b, &value.B) ||
@@ -113,8 +113,8 @@ FORCE_INLINE bool GuidParse(const StringViewType& text, Guid& value)
// FormatType::P
case 38:
{
- StringType b = text.Substring(10, 4) + text.Substring(15, 4);
- StringType c = text.Substring(20, 4) + text.Substring(25, 4);
+ StringType b = StringType(text.Substring(10, 4)) + text.Substring(15, 4);
+ StringType c = StringType(text.Substring(20, 4)) + text.Substring(25, 4);
return
text[0] != text[text.Length() - 1] ||
StringUtils::ParseHex(*text + 1, 8, &value.A) ||
diff --git a/Source/Engine/Core/Types/String.cpp b/Source/Engine/Core/Types/String.cpp
index 040bb9ab2..7919d513d 100644
--- a/Source/Engine/Core/Types/String.cpp
+++ b/Source/Engine/Core/Types/String.cpp
@@ -13,7 +13,18 @@ String::String(const StringAnsi& str)
String::String(const StringView& str)
{
- Set(str.Get(), str.Length());
+ _length = str.Length();
+ if (_length != 0)
+ {
+ ASSERT(_length > 0);
+ _data = (Char*)Platform::Allocate((_length + 1) * sizeof(Char), 16);
+ _data[_length] = 0;
+ Platform::MemoryCopy(_data, str.Get(), _length * sizeof(Char));
+ }
+ else
+ {
+ _data = nullptr;
+ }
}
String::String(const StringAnsiView& str)
@@ -38,7 +49,6 @@ void String::Set(const Char* chars, int32 length)
}
_length = length;
}
-
Platform::MemoryCopy(_data, chars, length * sizeof(Char));
}
@@ -58,7 +68,6 @@ void String::Set(const char* chars, int32 length)
}
_length = length;
}
-
if (chars)
StringUtils::ConvertANSI2UTF16(chars, _data, length);
}
diff --git a/Source/Engine/Core/Types/String.h b/Source/Engine/Core/Types/String.h
index 87babc637..d7d42f211 100644
--- a/Source/Engine/Core/Types/String.h
+++ b/Source/Engine/Core/Types/String.h
@@ -5,6 +5,7 @@
#include "Engine/Platform/Platform.h"
#include "Engine/Platform/StringUtils.h"
#include "Engine/Core/Formatting.h"
+#include "Engine/Core/Templates.h"
///
/// Represents text as a sequence of characters. Container uses a single dynamic memory allocation to store the characters data. Characters sequence is always null-terminated.
@@ -225,9 +226,7 @@ public:
const T* start = _data;
if (startPosition != -1)
start += startPosition < Length() ? startPosition : Length();
- const T* tmp = searchCase == StringSearchCase::IgnoreCase
- ? StringUtils::FindIgnoreCase(start, subStr)
- : StringUtils::Find(start, subStr);
+ const T* tmp = searchCase == StringSearchCase::IgnoreCase ? StringUtils::FindIgnoreCase(start, subStr) : StringUtils::Find(start, subStr);
return tmp ? static_cast(tmp - **this) : -1;
}
@@ -498,18 +497,19 @@ public:
}
///
- /// Resizes string contents, works like: *this = Left(length) but is faster.
+ /// Resizes string contents.
///
- /// New length of the string (amount of characters from left side to preserve).
+ /// New length of the string.
void Resize(int32 length)
{
- ASSERT(length >= 0 && length <= _length);
+ ASSERT(length >= 0);
if (_length != length)
{
const auto oldData = _data;
+ const auto minLength = _length < length ? _length : length;
_length = length;
_data = (T*)Platform::Allocate((length + 1) * sizeof(T), 16);
- Platform::MemoryCopy(_data, oldData, length * sizeof(T));
+ Platform::MemoryCopy(_data, oldData, minLength * sizeof(T));
_data[length] = 0;
Platform::Free(oldData);
}
@@ -540,6 +540,7 @@ public:
///
/// The reference to the string.
String(const String& str)
+ : String()
{
Set(str.Get(), str.Length());
}
@@ -577,6 +578,7 @@ public:
/// The ANSI string.
/// The ANSI string length.
explicit String(const char* str, int32 length)
+ : String()
{
Set(str, length);
}
@@ -586,8 +588,9 @@ public:
///
/// The UTF-16 string.
String(const Char* str)
- : String(str, StringUtils::Length(str))
+ : String()
{
+ Set(str, StringUtils::Length(str));
}
///
@@ -596,6 +599,7 @@ public:
/// The UTF-16 string.
/// The UTF-16 string length.
String(const Char* str, int32 length)
+ : String()
{
Set(str, length);
}
@@ -604,7 +608,7 @@ public:
/// Initializes a new instance of the class.
///
/// The other string.
- explicit String(const StringView& str);
+ String(const StringView& str);
///
/// Initializes a new instance of the class.
@@ -1111,7 +1115,17 @@ public:
/// The combined path.
FORCE_INLINE String operator/(const String& str) const
{
- return operator/(*str);
+ return String(*this) /= str;
+ }
+
+ ///
+ /// Concatenates this path with given path ensuring the '/' character is used between them.
+ ///
+ /// The string to be concatenated onto the end of this.
+ /// The combined path.
+ FORCE_INLINE String operator/(const StringView& str) const
+ {
+ return String(*this) /= str;
}
public:
diff --git a/Source/Engine/Core/Types/StringView.cpp b/Source/Engine/Core/Types/StringView.cpp
index e29afe4e8..8b30cc755 100644
--- a/Source/Engine/Core/Types/StringView.cpp
+++ b/Source/Engine/Core/Types/StringView.cpp
@@ -27,28 +27,28 @@ bool StringView::operator!=(const String& other) const
return StringUtils::Compare(this->GetText(), *other) != 0;
}
-String StringView::Left(int32 count) const
+StringView StringView::Left(int32 count) const
{
const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length();
- return String(**this, countClamped);
+ return StringView(**this, countClamped);
}
-String StringView::Right(int32 count) const
+StringView StringView::Right(int32 count) const
{
const int32 countClamped = count < 0 ? 0 : count < Length() ? count : Length();
- return String(**this + Length() - countClamped);
+ return StringView(**this + Length() - countClamped);
}
-String StringView::Substring(int32 startIndex) const
+StringView StringView::Substring(int32 startIndex) const
{
ASSERT(startIndex >= 0 && startIndex < Length());
- return String(Get() + startIndex, Length() - startIndex);
+ return StringView(Get() + startIndex, Length() - startIndex);
}
-String StringView::Substring(int32 startIndex, int32 count) const
+StringView StringView::Substring(int32 startIndex, int32 count) const
{
ASSERT(startIndex >= 0 && startIndex + count <= Length() && count >= 0);
- return String(Get() + startIndex, count);
+ return StringView(Get() + startIndex, count);
}
String StringView::ToString() const
diff --git a/Source/Engine/Core/Types/StringView.h b/Source/Engine/Core/Types/StringView.h
index b413ff552..e267b760e 100644
--- a/Source/Engine/Core/Types/StringView.h
+++ b/Source/Engine/Core/Types/StringView.h
@@ -66,7 +66,6 @@ public:
///
/// Returns true if string is empty.
///
- /// True if string is empty, otherwise false.
FORCE_INLINE bool IsEmpty() const
{
return _length == 0;
@@ -75,7 +74,6 @@ public:
///
/// Returns true if string isn't empty.
///
- /// True if string isn't empty, otherwise false.
FORCE_INLINE bool HasChars() const
{
return _length != 0;
@@ -84,7 +82,6 @@ public:
///
/// Gets the length of the string.
///
- /// The string length.
FORCE_INLINE int32 Length() const
{
return _length;
@@ -93,7 +90,6 @@ public:
///
/// Gets the pointer to the string.
///
- /// The string.
FORCE_INLINE const T* operator*() const
{
return _data;
@@ -102,7 +98,6 @@ public:
///
/// Gets the pointer to the string.
///
- /// The string.
FORCE_INLINE const T* Get() const
{
return _data;
@@ -111,7 +106,6 @@ public:
///
/// Gets the pointer to the string or to the static empty text if string is null. Returned pointer is always valid (read-only).
///
- /// The string handle.
FORCE_INLINE const T* GetText() const
{
return _data ? _data : (const T*)TEXT("");
@@ -160,16 +154,16 @@ public:
{
const int32 length = Length();
if (searchCase == StringSearchCase::IgnoreCase)
- return length > 0 && _data[0] == c;
- return length > 0 && StringUtils::ToLower(_data[0]) == StringUtils::ToLower(c);
+ return length > 0 && StringUtils::ToLower(_data[0]) == StringUtils::ToLower(c);
+ return length > 0 && _data[0] == c;
}
bool EndsWith(T c, StringSearchCase searchCase = StringSearchCase::IgnoreCase) const
{
const int32 length = Length();
if (searchCase == StringSearchCase::IgnoreCase)
- return length > 0 && _data[length - 1] == c;
- return length > 0 && StringUtils::ToLower(_data[length - 1]) == StringUtils::ToLower(c);
+ return length > 0 && StringUtils::ToLower(_data[length - 1]) == StringUtils::ToLower(c);
+ return length > 0 && _data[length - 1] == c;
}
bool StartsWith(const StringViewBase& prefix, StringSearchCase searchCase = StringSearchCase::IgnoreCase) const
@@ -326,21 +320,21 @@ public:
///
/// The characters count.
/// The substring.
- String Left(int32 count) const;
+ StringView Left(int32 count) const;
///
/// Gets the string of characters from the right (end of the string).
///
/// The characters count.
/// The substring.
- String Right(int32 count) const;
+ StringView Right(int32 count) const;
///
/// Retrieves substring created from characters starting from startIndex to the String end.
///
/// The index of the first character to subtract.
/// The substring created from String data.
- String Substring(int32 startIndex) const;
+ StringView Substring(int32 startIndex) const;
///
/// Retrieves substring created from characters starting from start index.
@@ -348,7 +342,7 @@ public:
/// The index of the first character to subtract.
/// The amount of characters to retrieve.
/// The substring created from String data.
- String Substring(int32 startIndex, int32 count) const;
+ StringView Substring(int32 startIndex, int32 count) const;
public:
diff --git a/Source/Engine/Core/Types/TimeSpan.h b/Source/Engine/Core/Types/TimeSpan.h
index 0b56d8ee1..cb663d80c 100644
--- a/Source/Engine/Core/Types/TimeSpan.h
+++ b/Source/Engine/Core/Types/TimeSpan.h
@@ -3,7 +3,6 @@
#pragma once
#include "BaseTypes.h"
-#include "Engine/Platform/Platform.h"
#include "Engine/Core/Formatting.h"
#include "Engine/Core/Templates.h"
diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp
index a3569ded9..b443577fb 100644
--- a/Source/Engine/Debug/DebugDraw.cpp
+++ b/Source/Engine/Debug/DebugDraw.cpp
@@ -12,11 +12,13 @@
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Graphics/GPUContext.h"
-#include "Engine/Graphics/RenderTask.h"
-#include "Engine/Graphics/DynamicBuffer.h"
+#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/GPUPipelineState.h"
-#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderBuffers.h"
+#include "Engine/Graphics/DynamicBuffer.h"
+#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
+#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Animations/AnimationUtils.h"
#include "Engine/Profiler/Profiler.h"
#include "Engine/Debug/DebugLog.h"
diff --git a/Source/Engine/Debug/DebugLog.cpp b/Source/Engine/Debug/DebugLog.cpp
index 9263651b9..fb0ab901b 100644
--- a/Source/Engine/Debug/DebugLog.cpp
+++ b/Source/Engine/Debug/DebugLog.cpp
@@ -7,6 +7,7 @@
#include "Engine/Scripting/ManagedCLR/MDomain.h"
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
#include "Engine/Scripting/ManagedCLR/MClass.h"
+#include "Engine/Threading/Threading.h"
#include "FlaxEngine.Gen.h"
#include
#include
diff --git a/Source/Engine/Debug/Exceptions/JsonParseException.h b/Source/Engine/Debug/Exceptions/JsonParseException.h
index 765d7855e..4e4b35962 100644
--- a/Source/Engine/Debug/Exceptions/JsonParseException.h
+++ b/Source/Engine/Debug/Exceptions/JsonParseException.h
@@ -25,7 +25,7 @@ namespace Log
/// Parsing error code.
/// Parsing error location.
JsonParseException(ErrorCode error, size_t offset)
- : JsonParseException(error, offset, String::Empty)
+ : JsonParseException(error, offset, StringView::Empty)
{
}
@@ -35,7 +35,7 @@ namespace Log
/// Parsing error code.
/// Parsing error location.
/// Additional information that help describe error
- JsonParseException(ErrorCode error, size_t offset, const String& additionalInfo)
+ JsonParseException(ErrorCode error, size_t offset, const StringView& additionalInfo)
: Exception(String::Format(TEXT("Parsing Json failed with error code {0} (offset {2}). {1}"), static_cast(error), GetParseError_En(error), offset), additionalInfo)
{
}
diff --git a/Source/Engine/Engine/Base/GameBase.cpp b/Source/Engine/Engine/Base/GameBase.cpp
index 62e187e7d..a4b10adf9 100644
--- a/Source/Engine/Engine/Base/GameBase.cpp
+++ b/Source/Engine/Engine/Base/GameBase.cpp
@@ -6,6 +6,7 @@
#include "Engine/Engine/Time.h"
#include "Engine/Engine/Engine.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Platform/Window.h"
#include "Engine/Profiler/Profiler.h"
#include "Engine/Level/Level.h"
@@ -17,6 +18,7 @@
#include "Engine/Graphics/RenderTask.h"
#include "Engine/Render2D/Render2D.h"
#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Utilities/Encryption.h"
#include "Engine/Core/Log.h"
#include "FlaxEngine.Gen.h"
@@ -241,7 +243,7 @@ void GameBaseImpl::OnPostRender(GPUContext* context, RenderContext& renderContex
const Rectangle screenRect(viewport.X, viewport.Y, viewport.Width, viewport.Height);
Rectangle imageArea = screenRect;
imageArea.Scale(0.6f);
- const float aspectRatio = static_cast(splashScreen->Width()) / splashScreen->Height();
+ const float aspectRatio = static_cast(splashScreen->Width()) / static_cast(splashScreen->Height());
const float height = imageArea.GetWidth() / aspectRatio;
imageArea.Location.Y += (imageArea.GetHeight() - height) * 0.5f;
imageArea.Size.Y = height;
diff --git a/Source/Engine/Engine/CommandLine.cpp b/Source/Engine/Engine/CommandLine.cpp
index edfc9c268..d6c03b070 100644
--- a/Source/Engine/Engine/CommandLine.cpp
+++ b/Source/Engine/Engine/CommandLine.cpp
@@ -109,7 +109,10 @@ bool CommandLine::Parse(const Char* cmdLine)
PARSE_BOOL_SWITCH("-novsync ", NoVSync);
PARSE_BOOL_SWITCH("-nolog ", NoLog);
PARSE_BOOL_SWITCH("-std ", Std);
+#if !BUILD_RELEASE
PARSE_ARG_SWITCH("-debug ", DebuggerAddress);
+ PARSE_BOOL_SWITCH("-debugwait ", WaitForDebugger);
+#endif
#if PLATFORM_HAS_HEADLESS_MODE
PARSE_BOOL_SWITCH("-headless ", Headless);
#endif
diff --git a/Source/Engine/Engine/CommandLine.h b/Source/Engine/Engine/CommandLine.h
index 278620bf5..62b38ca99 100644
--- a/Source/Engine/Engine/CommandLine.h
+++ b/Source/Engine/Engine/CommandLine.h
@@ -49,11 +49,20 @@ public:
///
Nullable Std;
+#if !BUILD_RELEASE
+
///
/// -debug !ip:port! (Mono debugger address)
///
Nullable DebuggerAddress;
+ ///
+ /// -debugwait (instructs Mono debugger to wait for client attach for 5 seconds)
+ ///
+ Nullable WaitForDebugger;
+
+#endif
+
#if PLATFORM_HAS_HEADLESS_MODE
///
diff --git a/Source/Engine/Engine/Engine.Build.cs b/Source/Engine/Engine/Engine.Build.cs
index 38db0e59c..0ee4e7a7c 100644
--- a/Source/Engine/Engine/Engine.Build.cs
+++ b/Source/Engine/Engine/Engine.Build.cs
@@ -35,6 +35,7 @@ public class Engine : EngineModule
options.PublicDependencies.Add("UI");
options.PublicDependencies.Add("Utilities");
options.PublicDependencies.Add("Visject");
+ options.PublicDependencies.Add("Localization");
// Use source folder per platform group
switch (options.Platform.Target)
diff --git a/Source/Engine/Engine/Engine.cpp b/Source/Engine/Engine/Engine.cpp
index 979a2547b..24d691c56 100644
--- a/Source/Engine/Engine/Engine.cpp
+++ b/Source/Engine/Engine/Engine.cpp
@@ -166,6 +166,7 @@ int32 Engine::Main(const Char* cmdLine)
}
}
#endif
+
// App paused logic
if (Platform::GetIsPaused())
{
@@ -202,6 +203,7 @@ int32 Engine::Main(const Char* cmdLine)
{
OnDraw();
Time::OnEndDraw();
+ FrameMark;
canDraw = false;
}
@@ -622,7 +624,7 @@ void EngineImpl::InitMainWindow()
if (exception)
{
MException ex(exception);
- ex.Log(LogType::Fatal, TEXT("FlaxEngine.ClassLibraryInitializer.SetWindow"));
+ ex.Log(LogType::Fatal, TEXT("FlaxEngine.Scripting.SetWindow"));
}
#endif
}
diff --git a/Source/Engine/Engine/EngineService.cpp b/Source/Engine/Engine/EngineService.cpp
index 90e9a8d78..9f653a0b8 100644
--- a/Source/Engine/Engine/EngineService.cpp
+++ b/Source/Engine/Engine/EngineService.cpp
@@ -4,6 +4,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Sorting.h"
+#include
static bool CompareEngineServices(EngineService* const& a, EngineService* const& b)
{
@@ -14,6 +15,7 @@ static bool CompareEngineServices(EngineService* const& a, EngineService* const&
void EngineService::name() { } \
void EngineService::On##name() \
{ \
+ ZoneScoped; \
auto& services = GetServices(); \
for (int32 i = 0; i < services.Count(); i++) \
services[i]->name(); \
@@ -22,6 +24,7 @@ static bool CompareEngineServices(EngineService* const& a, EngineService* const&
void EngineService::name() { } \
void EngineService::On##name() \
{ \
+ ZoneScoped; \
auto& services = GetServices(); \
for (int32 i = 0; i < services.Count(); i++) \
services[i]->name(); \
@@ -63,18 +66,33 @@ bool EngineService::Init()
void EngineService::OnInit()
{
+ ZoneScoped;
Sort();
// Init services from front to back
auto& services = GetServices();
+#if TRACY_ENABLE
+ Char nameBuffer[100];
+#endif
for (int32 i = 0; i < services.Count(); i++)
{
const auto service = services[i];
- LOG(Info, "Initialize {0}...", service->Name);
+ const StringView name(service->Name);
+#if TRACY_ENABLE
+ ZoneScoped;
+ int32 nameBufferLength = 0;
+ for (int32 j = 0; j < name.Length(); j++)
+ if (name[j] != ' ')
+ nameBuffer[nameBufferLength++] = name[j];
+ Platform::MemoryCopy(nameBuffer + nameBufferLength, TEXT("::Init"), 7 * sizeof(Char));
+ nameBufferLength += 7;
+ ZoneName(nameBuffer, nameBufferLength);
+#endif
+ LOG(Info, "Initialize {0}...", name);
service->IsInitialized = true;
if (service->Init())
{
- Platform::Fatal(String::Format(TEXT("Failed to initialize {0}."), service->Name));
+ Platform::Fatal(String::Format(TEXT("Failed to initialize {0}."), name));
}
}
@@ -87,6 +105,7 @@ void EngineService::Dispose()
void EngineService::OnDispose()
{
+ ZoneScoped;
// Dispose services from back to front
auto& services = GetServices();
for (int32 i = services.Count() - 1; i >= 0; i--)
diff --git a/Source/Engine/Engine/GameplayGlobals.cpp b/Source/Engine/Engine/GameplayGlobals.cpp
index f945832cc..0525f3169 100644
--- a/Source/Engine/Engine/GameplayGlobals.cpp
+++ b/Source/Engine/Engine/GameplayGlobals.cpp
@@ -8,6 +8,8 @@
#include "Engine/Content/Factories/BinaryAssetFactory.h"
#include "Engine/Content/Upgraders/BinaryAssetUpgrader.h"
+#if USE_EDITOR
+
class GameplayGlobalsUpgrader : public BinaryAssetUpgrader
{
public:
@@ -50,7 +52,9 @@ private:
}
};
-REGISTER_BINARY_ASSET(GameplayGlobals, "FlaxEngine.GameplayGlobals", ::New(), true);
+#endif
+
+REGISTER_BINARY_ASSET_WITH_UPGRADER(GameplayGlobals, "FlaxEngine.GameplayGlobals", GameplayGlobalsUpgrader, true);
GameplayGlobals::GameplayGlobals(const SpawnParams& params, const AssetInfo* info)
: BinaryAsset(params, info)
diff --git a/Source/Engine/Engine/Globals.cpp b/Source/Engine/Engine/Globals.cpp
index 9f180fa12..e65823350 100644
--- a/Source/Engine/Engine/Globals.cpp
+++ b/Source/Engine/Engine/Globals.cpp
@@ -25,4 +25,3 @@ int32 Globals::EngineBuildNumber = FLAXENGINE_VERSION_BUILD;
String Globals::ProductName;
String Globals::CompanyName;
int32 Globals::ContentKey;
-bool Globals::ConvertLoadedMaterialsByForce;
diff --git a/Source/Engine/Engine/Globals.h b/Source/Engine/Engine/Globals.h
index 16c47d8ee..6d88b11bf 100644
--- a/Source/Engine/Engine/Globals.h
+++ b/Source/Engine/Engine/Globals.h
@@ -94,7 +94,4 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Globals);
/// The content data keycode.
///
static int32 ContentKey;
-
- // True if convert all loaded material by force
- static bool ConvertLoadedMaterialsByForce;
};
diff --git a/Source/Engine/Engine/Linux/LinuxGame.cpp b/Source/Engine/Engine/Linux/LinuxGame.cpp
index 1f59a66a9..3fe7c6a92 100644
--- a/Source/Engine/Engine/Linux/LinuxGame.cpp
+++ b/Source/Engine/Engine/Linux/LinuxGame.cpp
@@ -7,6 +7,7 @@
#include "Engine/Platform/FileSystem.h"
#include "Engine/Core/Config/PlatformSettings.h"
#include "Engine/Engine/CommandLine.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Graphics/Textures/TextureData.h"
// hack using TextureTool in Platform module -> TODO: move texture data sampling to texture data itself
#define COMPILE_WITH_TEXTURE_TOOL 1
diff --git a/Source/Engine/Foliage/Foliage.cpp b/Source/Engine/Foliage/Foliage.cpp
index c38191adf..bb809d4e0 100644
--- a/Source/Engine/Foliage/Foliage.cpp
+++ b/Source/Engine/Foliage/Foliage.cpp
@@ -5,6 +5,7 @@
#include "FoliageCluster.h"
#include "Engine/Core/Random.h"
#include "Engine/Engine/Engine.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/SceneQuery.h"
#include "Engine/Profiler/ProfilerCPU.h"
diff --git a/Source/Engine/Graphics/GPUDevice.cpp b/Source/Engine/Graphics/GPUDevice.cpp
index 51d92cd3f..8f30dc85a 100644
--- a/Source/Engine/Graphics/GPUDevice.cpp
+++ b/Source/Engine/Graphics/GPUDevice.cpp
@@ -6,6 +6,7 @@
#include "RenderTask.h"
#include "RenderTools.h"
#include "Graphics.h"
+#include "Shaders/GPUShader.h"
#include "Async/DefaultGPUTasksExecutor.h"
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/Assets/Material.h"
diff --git a/Source/Engine/Graphics/Materials/DecalMaterialShader.h b/Source/Engine/Graphics/Materials/DecalMaterialShader.h
index 0baf88b42..a84960576 100644
--- a/Source/Engine/Graphics/Materials/DecalMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DecalMaterialShader.h
@@ -33,7 +33,7 @@ public:
/// Init
///
/// Material resource name
- DecalMaterialShader(const String& name)
+ DecalMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
index 537547c6a..b8886769d 100644
--- a/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DeferredMaterialShader.h
@@ -56,7 +56,7 @@ private:
public:
- DeferredMaterialShader(const String& name)
+ DeferredMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/DeformableMaterialShader.h b/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
index f2c796a23..c3040ded3 100644
--- a/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/DeformableMaterialShader.h
@@ -44,7 +44,7 @@ private:
public:
- DeformableMaterialShader(const String& name)
+ DeformableMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
index bcba48259..dd053717f 100644
--- a/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/ForwardMaterialShader.h
@@ -58,7 +58,7 @@ public:
/// Init
///
/// Material resource name
- ForwardMaterialShader(const String& name)
+ ForwardMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/GUIMaterialShader.h b/Source/Engine/Graphics/Materials/GUIMaterialShader.h
index c84373c90..ead9cf4a9 100644
--- a/Source/Engine/Graphics/Materials/GUIMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/GUIMaterialShader.h
@@ -33,7 +33,7 @@ public:
/// Init
///
/// Material resource name
- GUIMaterialShader(const String& name)
+ GUIMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/MaterialParams.cpp b/Source/Engine/Graphics/Materials/MaterialParams.cpp
index 5ce55f1c4..b5ff66c3b 100644
--- a/Source/Engine/Graphics/Materials/MaterialParams.cpp
+++ b/Source/Engine/Graphics/Materials/MaterialParams.cpp
@@ -2,6 +2,8 @@
#include "MaterialParams.h"
#include "MaterialInfo.h"
+#include "Engine/Core/Math/Vector4.h"
+#include "Engine/Core/Math/Matrix.h"
#include "Engine/Content/Content.h"
#include "Engine/Graphics/GPUContext.h"
#include "Engine/Engine/GameplayGlobals.h"
@@ -96,11 +98,11 @@ Variant MaterialParameter::GetValue() const
case MaterialParameterType::Vector3:
return _asVector3;
case MaterialParameterType::Vector4:
- return _asVector4;
+ return *(Vector4*)&AsData;
case MaterialParameterType::Color:
return _asColor;
case MaterialParameterType::Matrix:
- return Variant(_asMatrix);
+ return Variant(*(Matrix*)&AsData);
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
case MaterialParameterType::CubeTexture:
@@ -140,13 +142,13 @@ void MaterialParameter::SetValue(const Variant& value)
_asVector3 = (Vector3)value;
break;
case MaterialParameterType::Vector4:
- _asVector4 = (Vector4)value;
+ *(Vector4*)&AsData = (Vector4)value;
break;
case MaterialParameterType::Color:
_asColor = (Color)value;
break;
case MaterialParameterType::Matrix:
- _asMatrix = (Matrix)value;
+ *(Matrix*)&AsData = (Matrix)value;
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
@@ -245,13 +247,13 @@ void MaterialParameter::Bind(BindMeta& meta) const
*((Vector3*)(meta.Constants + _offset)) = _asVector3;
break;
case MaterialParameterType::Vector4:
- *((Vector4*)(meta.Constants + _offset)) = _asVector4;
+ *((Vector4*)(meta.Constants + _offset)) = *(Vector4*)&AsData;
break;
case MaterialParameterType::Color:
*((Color*)(meta.Constants + _offset)) = _asColor;
break;
case MaterialParameterType::Matrix:
- Matrix::Transpose(_asMatrix, *(Matrix*)(meta.Constants + _offset));
+ Matrix::Transpose(*(Matrix*)&AsData, *(Matrix*)(meta.Constants + _offset));
break;
case MaterialParameterType::NormalMap:
{
@@ -406,13 +408,13 @@ void MaterialParameter::clone(const MaterialParameter* param)
_asVector3 = param->_asVector3;
break;
case MaterialParameterType::Vector4:
- _asVector4 = param->_asVector4;
+ *(Vector4*)&AsData = *(Vector4*)¶m->AsData;
break;
case MaterialParameterType::Color:
_asColor = param->_asColor;
break;
case MaterialParameterType::Matrix:
- _asMatrix = param->_asMatrix;
+ *(Matrix*)&AsData = *(Matrix*)¶m->AsData;
break;
default:
break;
@@ -585,13 +587,13 @@ bool MaterialParams::Load(ReadStream* stream)
stream->Read(¶m->_asVector3);
break;
case MaterialParameterType::Vector4:
- stream->Read(¶m->_asVector4);
+ stream->Read((Vector4*)¶m->AsData);
break;
case MaterialParameterType::Color:
stream->Read(¶m->_asColor);
break;
case MaterialParameterType::Matrix:
- stream->Read(¶m->_asMatrix);
+ stream->Read((Matrix*)¶m->AsData);
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
@@ -658,13 +660,13 @@ bool MaterialParams::Load(ReadStream* stream)
stream->Read(¶m->_asVector3);
break;
case MaterialParameterType::Vector4:
- stream->Read(¶m->_asVector4);
+ stream->Read((Vector4*)¶m->AsData);
break;
case MaterialParameterType::Color:
stream->Read(¶m->_asColor);
break;
case MaterialParameterType::Matrix:
- stream->Read(¶m->_asMatrix);
+ stream->Read((Matrix*)¶m->AsData);
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
@@ -732,13 +734,13 @@ bool MaterialParams::Load(ReadStream* stream)
stream->Read(¶m->_asVector3);
break;
case MaterialParameterType::Vector4:
- stream->Read(¶m->_asVector4);
+ stream->Read((Vector4*)¶m->AsData);
break;
case MaterialParameterType::Color:
stream->Read(¶m->_asColor);
break;
case MaterialParameterType::Matrix:
- stream->Read(¶m->_asMatrix);
+ stream->Read((Matrix*)¶m->AsData);
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
@@ -824,13 +826,13 @@ void MaterialParams::Save(WriteStream* stream)
stream->Write(¶m->_asVector3);
break;
case MaterialParameterType::Vector4:
- stream->Write(¶m->_asVector4);
+ stream->Write((Vector4*)¶m->AsData);
break;
case MaterialParameterType::Color:
stream->Write(¶m->_asColor);
break;
case MaterialParameterType::Matrix:
- stream->Write(¶m->_asMatrix);
+ stream->Write((Matrix*)¶m->AsData);
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
@@ -898,13 +900,13 @@ void MaterialParams::Save(WriteStream* stream, const ArrayWrite(¶m.AsVector3);
break;
case MaterialParameterType::Vector4:
- stream->Write(¶m.AsVector4);
+ stream->Write((Vector4*)¶m.AsData);
break;
case MaterialParameterType::Color:
stream->Write(¶m.AsColor);
break;
case MaterialParameterType::Matrix:
- stream->Write(¶m.AsMatrix);
+ stream->Write((Matrix*)¶m.AsData);
break;
case MaterialParameterType::NormalMap:
case MaterialParameterType::Texture:
diff --git a/Source/Engine/Graphics/Materials/MaterialParams.h b/Source/Engine/Graphics/Materials/MaterialParams.h
index c51ffb8f9..d4fef1966 100644
--- a/Source/Engine/Graphics/Materials/MaterialParams.h
+++ b/Source/Engine/Graphics/Materials/MaterialParams.h
@@ -2,7 +2,9 @@
#pragma once
-#include "Engine/Core/Math/Matrix.h"
+#include "Engine/Core/Math/Color.h"
+#include "Engine/Core/Math/Vector2.h"
+#include "Engine/Core/Math/Vector3.h"
#include "Engine/Core/Types/StringView.h"
#include "Engine/Core/Collections/Array.h"
#include "Engine/Scripting/ScriptingObjectReference.h"
@@ -12,6 +14,7 @@
class MaterialInstance;
class MaterialParams;
class GPUContext;
+class GPUTextureView;
class RenderBuffers;
struct MaterialParamsLink
@@ -143,10 +146,9 @@ struct SerializedMaterialParam
float AsFloat;
Vector2 AsVector2;
Vector3 AsVector3;
- Vector4 AsVector4;
Color AsColor;
Guid AsGuid;
- Matrix AsMatrix;
+ byte AsData[16 * 4];
};
byte RegisterIndex;
@@ -181,9 +183,8 @@ private:
float _asFloat;
Vector2 _asVector2;
Vector3 _asVector3;
- Vector4 _asVector4;
Color _asColor;
- Matrix _asMatrix;
+ byte AsData[16 * 4];
};
AssetReference _asAsset;
diff --git a/Source/Engine/Graphics/Materials/MaterialShader.cpp b/Source/Engine/Graphics/Materials/MaterialShader.cpp
index 5191357ad..91c4fe8b8 100644
--- a/Source/Engine/Graphics/Materials/MaterialShader.cpp
+++ b/Source/Engine/Graphics/Materials/MaterialShader.cpp
@@ -54,7 +54,7 @@ GPUPipelineState* MaterialShader::PipelineStateCache::InitPS(CullMode mode, bool
return ps;
}
-MaterialShader::MaterialShader(const String& name)
+MaterialShader::MaterialShader(const StringView& name)
: _isLoaded(false)
, _shader(nullptr)
{
@@ -68,7 +68,7 @@ MaterialShader::~MaterialShader()
SAFE_DELETE_GPU_RESOURCE(_shader);
}
-MaterialShader* MaterialShader::Create(const String& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info)
+MaterialShader* MaterialShader::Create(const StringView& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info)
{
MaterialShader* material;
switch (info.Domain)
diff --git a/Source/Engine/Graphics/Materials/MaterialShader.h b/Source/Engine/Graphics/Materials/MaterialShader.h
index 8c49389a7..af0045f04 100644
--- a/Source/Engine/Graphics/Materials/MaterialShader.h
+++ b/Source/Engine/Graphics/Materials/MaterialShader.h
@@ -72,7 +72,7 @@ protected:
/// Init
///
/// Material resource name
- MaterialShader(const String& name);
+ MaterialShader(const StringView& name);
public:
@@ -90,7 +90,7 @@ public:
/// Stream with compiled shader data
/// Loaded material info structure
/// The created and loaded material or null if failed.
- static MaterialShader* Create(const String& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
+ static MaterialShader* Create(const StringView& name, MemoryReadStream& shaderCacheStream, const MaterialInfo& info);
///
/// Creates the dummy material used by the Null rendering backend to mock object but not perform any rendering.
diff --git a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp
index abc28a0de..2c5dc147a 100644
--- a/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp
+++ b/Source/Engine/Graphics/Materials/MaterialShaderFeatures.cpp
@@ -2,6 +2,7 @@
#include "MaterialShaderFeatures.h"
#include "Engine/Graphics/RenderTask.h"
+#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Renderer/ShadowsPass.h"
#if USE_EDITOR
diff --git a/Source/Engine/Graphics/Materials/ParticleMaterialShader.h b/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
index a38bf56f0..28a52ddf5 100644
--- a/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/ParticleMaterialShader.h
@@ -54,7 +54,7 @@ public:
/// Init
///
/// Material resource name
- ParticleMaterialShader(const String& name)
+ ParticleMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/PostFxMaterialShader.h b/Source/Engine/Graphics/Materials/PostFxMaterialShader.h
index 85767736f..0fdc5d416 100644
--- a/Source/Engine/Graphics/Materials/PostFxMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/PostFxMaterialShader.h
@@ -31,7 +31,7 @@ public:
/// Init
///
/// Material resource name
- PostFxMaterialShader(const String& name)
+ PostFxMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/TerrainMaterialShader.h b/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
index f69fc48ba..519233807 100644
--- a/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/TerrainMaterialShader.h
@@ -48,7 +48,7 @@ public:
/// Init
///
/// Material resource name
- TerrainMaterialShader(const String& name)
+ TerrainMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.h b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.h
index e38944342..5cf69fecb 100644
--- a/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.h
+++ b/Source/Engine/Graphics/Materials/VolumeParticleMaterialShader.h
@@ -19,7 +19,7 @@ public:
/// Init
///
/// Material resource name
- VolumeParticleMaterialShader(const String& name)
+ VolumeParticleMaterialShader(const StringView& name)
: MaterialShader(name)
{
}
diff --git a/Source/Engine/Graphics/Models/Mesh.cpp b/Source/Engine/Graphics/Models/Mesh.cpp
index 4454a44ce..dddbd6a3e 100644
--- a/Source/Engine/Graphics/Models/Mesh.cpp
+++ b/Source/Engine/Graphics/Models/Mesh.cpp
@@ -5,6 +5,8 @@
#include "Engine/Content/Assets/Material.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Graphics/GPUContext.h"
+#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Serialization/MemoryReadStream.h"
@@ -131,6 +133,11 @@ namespace
}
}
+bool Mesh::HasVertexColors() const
+{
+ return _vertexBuffers[2] != nullptr && _vertexBuffers[2]->IsAllocated();
+}
+
bool Mesh::UpdateMesh(uint32 vertexCount, uint32 triangleCount, VB0ElementType* vb0, VB1ElementType* vb1, VB2ElementType* vb2, void* ib, bool use16BitIndices)
{
auto model = (Model*)_model;
diff --git a/Source/Engine/Graphics/Models/Mesh.h b/Source/Engine/Graphics/Models/Mesh.h
index f378f9f8e..ca5174f7b 100644
--- a/Source/Engine/Graphics/Models/Mesh.h
+++ b/Source/Engine/Graphics/Models/Mesh.h
@@ -3,15 +3,16 @@
#pragma once
#include "MeshBase.h"
-#include "Engine/Renderer/RenderList.h"
-#include "Engine/Graphics/RenderTask.h"
#include "ModelInstanceEntry.h"
#include "Config.h"
#include "Types.h"
+#include "Engine/Level/Types.h"
#if USE_PRECISE_MESH_INTERSECTS
#include "CollisionProxy.h"
#endif
+struct GeometryDrawStateData;
+class Lightmap;
class GPUBuffer;
///
@@ -21,7 +22,6 @@ API_CLASS(NoSpawn) class FLAXENGINE_API Mesh : public MeshBase
{
DECLARE_SCRIPTING_TYPE_WITH_CONSTRUCTOR_IMPL(Mesh, MeshBase);
protected:
-
int32 _index;
int32 _lodIndex;
bool _hasLightmapUVs;
@@ -32,7 +32,6 @@ protected:
#endif
public:
-
Mesh(const Mesh& other)
: Mesh()
{
@@ -47,7 +46,6 @@ public:
~Mesh();
public:
-
///
/// Gets the model owning this mesh.
///
@@ -104,10 +102,7 @@ public:
/// Determines whether this mesh has a vertex colors buffer.
///
/// True if this mesh has a vertex colors buffers.
- API_PROPERTY() FORCE_INLINE bool HasVertexColors() const
- {
- return _vertexBuffers[2] != nullptr && _vertexBuffers[2]->IsAllocated();
- }
+ API_PROPERTY() bool HasVertexColors() const;
///
/// Determines whether this mesh contains valid lightmap texture coordinates data.
@@ -132,7 +127,6 @@ public:
#endif
public:
-
///
/// Updates the model mesh (used by the virtual models created with Init rather than Load).
///
@@ -211,7 +205,6 @@ public:
bool UpdateMesh(uint32 vertexCount, uint32 triangleCount, Vector3* vertices, uint32* triangles, Vector3* normals = nullptr, Vector3* tangents = nullptr, Vector2* uvs = nullptr, Color32* colors = nullptr);
public:
-
///
/// Updates the model mesh index buffer (used by the virtual models created with Init rather than Load).
///
@@ -244,7 +237,6 @@ public:
bool UpdateTriangles(uint32 triangleCount, void* ib, bool use16BitIndices);
public:
-
///
/// Initializes instance of the class.
///
@@ -276,7 +268,6 @@ public:
void Unload();
public:
-
///
/// Determines if there is an intersection between the mesh and a ray in given world
///
@@ -297,7 +288,6 @@ public:
}
public:
-
///
/// Gets the draw call geometry for this mesh. Sets the index and vertex buffers.
///
@@ -397,14 +387,12 @@ public:
void Draw(const RenderContext& renderContext, const DrawInfo& info, float lodDitherFactor) const;
public:
-
// [MeshBase]
bool DownloadDataGPU(MeshBufferType type, BytesContainer& result) const override;
Task* DownloadDataGPUAsync(MeshBufferType type, BytesContainer& result) const override;
bool DownloadDataCPU(MeshBufferType type, BytesContainer& result) const override;
private:
-
// Internal bindings
API_FUNCTION(NoProxy) ScriptingObject* GetParentModel();
API_FUNCTION(NoProxy) bool UpdateMeshInt(int32 vertexCount, int32 triangleCount, MonoArray* verticesObj, MonoArray* trianglesObj, MonoArray* normalsObj, MonoArray* tangentsObj, MonoArray* uvObj, MonoArray* colorsObj);
diff --git a/Source/Engine/Graphics/Models/ModelData.Tool.cpp b/Source/Engine/Graphics/Models/ModelData.Tool.cpp
index 8439a30d1..8faa9dcaa 100644
--- a/Source/Engine/Graphics/Models/ModelData.Tool.cpp
+++ b/Source/Engine/Graphics/Models/ModelData.Tool.cpp
@@ -6,6 +6,7 @@
#include "Engine/Core/Log.h"
#include "Engine/Core/Utilities.h"
#include "Engine/Core/Types/DateTime.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Core/Collections/BitArray.h"
#include "Engine/Tools/ModelTool/ModelTool.h"
#include "Engine/Tools/ModelTool/VertexTriangleAdjacency.h"
diff --git a/Source/Engine/Graphics/Models/SkeletonData.h b/Source/Engine/Graphics/Models/SkeletonData.h
index 5f336d8be..3e5700304 100644
--- a/Source/Engine/Graphics/Models/SkeletonData.h
+++ b/Source/Engine/Graphics/Models/SkeletonData.h
@@ -5,6 +5,8 @@
#include "Engine/Core/Math/Transform.h"
#include "Engine/Core/Math/Matrix.h"
#include "Engine/Core/Types/String.h"
+#include "Engine/Core/Types/StringView.h"
+#include "Engine/Core/Collections/Array.h"
///
/// Describes a single skeleton node data. Used by the runtime.
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.cpp b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
index 41d7cfb5b..f2d1134d9 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.cpp
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.cpp
@@ -4,6 +4,8 @@
#include "ModelInstanceEntry.h"
#include "Engine/Content/Assets/Material.h"
#include "Engine/Content/Assets/SkinnedModel.h"
+#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Serialization/MemoryReadStream.h"
diff --git a/Source/Engine/Graphics/Models/SkinnedMesh.h b/Source/Engine/Graphics/Models/SkinnedMesh.h
index c61b0a794..eb854189e 100644
--- a/Source/Engine/Graphics/Models/SkinnedMesh.h
+++ b/Source/Engine/Graphics/Models/SkinnedMesh.h
@@ -3,13 +3,13 @@
#pragma once
#include "MeshBase.h"
-#include "Engine/Renderer/RenderList.h"
-#include "Engine/Graphics/RenderTask.h"
-#include "ModelInstanceEntry.h"
#include "Types.h"
#include "BlendShape.h"
+struct GeometryDrawStateData;
+struct RenderContext;
class GPUBuffer;
+class SkinnedMeshDrawData;
///
/// Represents part of the skinned model that is made of vertices and can be rendered using custom material, transformation and skeleton bones hierarchy.
diff --git a/Source/Engine/Graphics/Models/SkinnedModelLOD.cpp b/Source/Engine/Graphics/Models/SkinnedModelLOD.cpp
index db0e8b86e..e2a43d085 100644
--- a/Source/Engine/Graphics/Models/SkinnedModelLOD.cpp
+++ b/Source/Engine/Graphics/Models/SkinnedModelLOD.cpp
@@ -5,6 +5,12 @@
#include "Engine/Content/Assets/Model.h"
#include "Engine/Serialization/MemoryReadStream.h"
+bool SkinnedModelLOD::HasAnyMeshInitialized() const
+{
+ // Note: we initialize all meshes at once so the last one can be used to check it.
+ return Meshes.HasItems() && Meshes.Last().IsInitialized();
+}
+
bool SkinnedModelLOD::Load(MemoryReadStream& stream)
{
// Load LOD for each mesh
diff --git a/Source/Engine/Graphics/Models/SkinnedModelLOD.h b/Source/Engine/Graphics/Models/SkinnedModelLOD.h
index 673bbb4e2..758db0a1b 100644
--- a/Source/Engine/Graphics/Models/SkinnedModelLOD.h
+++ b/Source/Engine/Graphics/Models/SkinnedModelLOD.h
@@ -33,12 +33,7 @@ public:
///
/// Determines whether any mesh has been initialized.
///
- /// True if any mesh has been initialized, otherwise false.
- FORCE_INLINE bool HasAnyMeshInitialized() const
- {
- // Note: we initialize all meshes at once so the last one can be used to check it.
- return Meshes.HasItems() && Meshes.Last().IsInitialized();
- }
+ bool HasAnyMeshInitialized() const;
public:
diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h
index 400deb3c1..e1607906f 100644
--- a/Source/Engine/Graphics/PostProcessSettings.h
+++ b/Source/Engine/Graphics/PostProcessSettings.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Core/Math/Vector3.h"
+#include "Engine/Core/Math/Vector4.h"
#include "Engine/Content/AssetReference.h"
#include "Engine/Serialization/ISerializable.h"
#include "Engine/Content/Assets/Texture.h"
diff --git a/Source/Engine/Graphics/RenderTask.h b/Source/Engine/Graphics/RenderTask.h
index 96048bcc2..86fa20856 100644
--- a/Source/Engine/Graphics/RenderTask.h
+++ b/Source/Engine/Graphics/RenderTask.h
@@ -84,7 +84,7 @@ public:
///
/// The index of the frame when this task was last time rendered.
///
- uint64 LastUsedFrame = 0;
+ API_FIELD(ReadOnly) uint64 LastUsedFrame = 0;
///
/// Action fired on task rendering.
diff --git a/Source/Engine/Graphics/RenderTools.cpp b/Source/Engine/Graphics/RenderTools.cpp
index c14a18c40..142906192 100644
--- a/Source/Engine/Graphics/RenderTools.cpp
+++ b/Source/Engine/Graphics/RenderTools.cpp
@@ -6,6 +6,7 @@
#include "PixelFormat.h"
#include "RenderView.h"
#include "GPUDevice.h"
+#include "RenderTask.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Engine/Time.h"
diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp
index 4d8b8cf1d..8ce11ec70 100644
--- a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp
+++ b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.cpp
@@ -4,6 +4,8 @@
#include "ShaderStorage.h"
#include "ShaderCacheManager.h"
#include "Engine/Engine/CommandLine.h"
+#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/Shaders/GPUShader.h"
#include "Engine/Serialization/MemoryReadStream.h"
#include "Engine/ShadowsOfMordor/AtlasChartsPacker.h"
@@ -31,6 +33,16 @@ ShaderStorage::CachingMode ShaderStorage::GetCachingMode()
#endif
+bool ShaderAssetBase::IsNullRenderer()
+{
+ return GPUDevice::Instance->GetRendererType() == RendererType::Null;
+}
+
+int32 ShaderAssetBase::GetCacheChunkIndex()
+{
+ return GetCacheChunkIndex(GPUDevice::Instance->GetShaderProfile());
+}
+
int32 ShaderAssetBase::GetCacheChunkIndex(ShaderProfile profile)
{
int32 result;
@@ -61,6 +73,28 @@ int32 ShaderAssetBase::GetCacheChunkIndex(ShaderProfile profile)
return result;
}
+bool ShaderAssetBase::initBase(AssetInitData& initData)
+{
+ // Validate version
+ if (initData.SerializedVersion != ShaderStorage::Header::Version)
+ {
+ LOG(Warning, "Invalid shader serialized version.");
+ return true;
+ }
+
+ // Validate data
+ if (initData.CustomData.Length() != sizeof(_shaderHeader))
+ {
+ LOG(Warning, "Invalid shader header.");
+ return true;
+ }
+
+ // Load header 'as-is'
+ Platform::MemoryCopy(&_shaderHeader, initData.CustomData.Get(), sizeof(_shaderHeader));
+
+ return false;
+}
+
#if USE_EDITOR
bool ShaderAssetBase::Save()
diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h
index ab1f79aee..a2b81bf5e 100644
--- a/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h
+++ b/Source/Engine/Graphics/Shaders/Cache/ShaderAssetBase.h
@@ -4,7 +4,6 @@
#include "Engine/Core/Types/DataContainer.h"
#include "Engine/Content/BinaryAsset.h"
-#include "Engine/Graphics/GPUDevice.h"
#include "ShaderStorage.h"
///
@@ -18,17 +17,15 @@ protected:
public:
- ///
- /// Gets internal shader cache chunk index
- ///
- /// Chunk index
- FORCE_INLINE static int32 GetCacheChunkIndex()
- {
- return GetCacheChunkIndex(GPUDevice::Instance->GetShaderProfile());
- }
+ static bool IsNullRenderer();
///
- /// Gets internal shader cache chunk index
+ /// Gets internal shader cache chunk index (for current GPU device shader profile).
+ ///
+ static int32 GetCacheChunkIndex();
+
+ ///
+ /// Gets internal shader cache chunk index.
///
/// Shader profile
/// Chunk index
@@ -47,11 +44,12 @@ public:
#endif
protected:
-
+
+ bool initBase(AssetInitData& initData);
+
///
/// Gets the parent asset.
///
- /// The asset.
virtual BinaryAsset* GetShaderAsset() const = 0;
#if USE_EDITOR
@@ -110,7 +108,7 @@ protected:
};
///
-/// Base class for assets that can contain shader
+/// Base class for binary assets that can contain shader.
///
template
class ShaderAssetTypeBase : public BaseType, public ShaderAssetBase
@@ -121,11 +119,6 @@ public:
protected:
- ///
- /// Init
- ///
- /// Asset scripting class metadata
- /// Asset information
explicit ShaderAssetTypeBase(const ScriptingObjectSpawnParams& params, const AssetInfo* info)
: BaseType(params, info)
{
@@ -134,38 +127,22 @@ protected:
protected:
// [BaseType]
- BinaryAsset* GetShaderAsset() const override
- {
- return (BinaryAsset*)this;
- }
bool init(AssetInitData& initData) override
{
- // Validate version
- if (initData.SerializedVersion != ShadersSerializedVersion)
- {
- LOG(Warning, "Invalid shader serialized version.");
- return true;
- }
-
- // Validate data
- if (initData.CustomData.Length() != sizeof(_shaderHeader))
- {
- LOG(Warning, "Invalid shader header.");
- return true;
- }
-
- // Load header 'as-is'
- Platform::MemoryCopy(&_shaderHeader, initData.CustomData.Get(), sizeof(_shaderHeader));
-
- return false;
+ return initBase(initData);
}
-
AssetChunksFlag getChunksToPreload() const override
{
AssetChunksFlag result = 0;
const auto cachingMode = ShaderStorage::GetCachingMode();
- if (cachingMode == ShaderStorage::CachingMode::AssetInternal && GPUDevice::Instance->GetRendererType() != RendererType::Null)
+ if (cachingMode == ShaderStorage::CachingMode::AssetInternal && !IsNullRenderer())
result |= GET_CHUNK_FLAG(GetCacheChunkIndex());
return result;
}
+
+ // [ShaderAssetBase]
+ BinaryAsset* GetShaderAsset() const override
+ {
+ return (BinaryAsset*)this;
+ }
};
diff --git a/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp b/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp
index 92fa47e8c..cd63b3ec4 100644
--- a/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp
+++ b/Source/Engine/Graphics/Shaders/Cache/ShaderCacheManager.cpp
@@ -233,7 +233,7 @@ bool ShaderCacheManagerService::Init()
{
LOG(Warning, "Shaders cache database is invalid. Performing reset.");
- if (FileSystem::DeleteDirectory(rootDir))
+ if (FileSystem::DirectoryExists(rootDir) && FileSystem::DeleteDirectory(rootDir))
{
LOG(Warning, "Failed to reset the shaders cache database.");
}
diff --git a/Source/Engine/Graphics/Textures/ITextureOwner.h b/Source/Engine/Graphics/Textures/ITextureOwner.h
index 8f66298ba..196b76664 100644
--- a/Source/Engine/Graphics/Textures/ITextureOwner.h
+++ b/Source/Engine/Graphics/Textures/ITextureOwner.h
@@ -18,8 +18,7 @@ public:
///
/// Gets the texture owner mutex used to synchronize texture logic.
///
- /// The mutex.
- virtual CriticalSection* GetOwnerLocker() const = 0;
+ virtual CriticalSection& GetOwnerLocker() const = 0;
///
/// Get texture mip map data
diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.cpp b/Source/Engine/Graphics/Textures/StreamingTexture.cpp
index 15b9c540c..d5a1e9339 100644
--- a/Source/Engine/Graphics/Textures/StreamingTexture.cpp
+++ b/Source/Engine/Graphics/Textures/StreamingTexture.cpp
@@ -33,6 +33,23 @@ StreamingTexture::~StreamingTexture()
ASSERT(_streamingTasksCount == 0);
}
+Vector2 StreamingTexture::Size() const
+{
+ return _texture->Size();
+}
+
+int32 StreamingTexture::TextureMipIndexToTotalIndex(int32 textureMipIndex) const
+{
+ const int32 missingMips = TotalMipLevels() - _texture->MipLevels();
+ return textureMipIndex + missingMips;
+}
+
+int32 StreamingTexture::TotalIndexToTextureMipIndex(int32 mipIndex) const
+{
+ const int32 missingMips = TotalMipLevels() - _texture->MipLevels();
+ return mipIndex - missingMips;
+}
+
bool StreamingTexture::Create(const TextureHeader& header)
{
// Validate header (further validation is performed by the Texture.Init)
@@ -90,13 +107,27 @@ uint64 StreamingTexture::GetTotalMemoryUsage() const
return CalculateTextureMemoryUsage(_header.Format, _header.Width, _header.Height, _header.MipLevels) * arraySize;
}
+String StreamingTexture::ToString() const
+{
+ return _texture->ToString();
+}
+
+int32 StreamingTexture::GetCurrentResidency() const
+{
+ return _texture->ResidentMipLevels();
+}
+
+int32 StreamingTexture::GetAllocatedResidency() const
+{
+ return _texture->MipLevels();
+}
+
bool StreamingTexture::CanBeUpdated() const
{
// Streaming Texture cannot be updated if:
// - is not initialized
// - mip data uploading job running
// - resize texture job running
-
return IsInitialized() && Platform::AtomicRead(&_streamingTasksCount) == 0;
}
@@ -146,7 +177,6 @@ protected:
return Result::Ok;
}
-
void OnEnd() override
{
Platform::InterlockedDecrement(&_streamingTexture->_streamingTasksCount);
@@ -154,7 +184,6 @@ protected:
// Base
GPUTask::OnEnd();
}
-
void OnSync() override
{
Swap(_streamingTexture->_texture, _newTexture);
@@ -298,7 +327,6 @@ protected:
return Result::Ok;
}
-
void OnEnd() override
{
_dataLock.Release();
diff --git a/Source/Engine/Graphics/Textures/StreamingTexture.h b/Source/Engine/Graphics/Textures/StreamingTexture.h
index 3b6e94959..1dda71ba4 100644
--- a/Source/Engine/Graphics/Textures/StreamingTexture.h
+++ b/Source/Engine/Graphics/Textures/StreamingTexture.h
@@ -2,7 +2,6 @@
#pragma once
-#include "GPUTexture.h"
#include "ITextureOwner.h"
#include "Engine/Streaming/StreamableResource.h"
#include "Types.h"
@@ -14,7 +13,6 @@ class FLAXENGINE_API StreamingTexture : public Object, public StreamableResource
{
friend class StreamTextureMipTask;
friend class StreamTextureResizeTask;
-
protected:
ITextureOwner* _owner;
@@ -25,16 +23,7 @@ protected:
public:
- ///
- /// Init
- ///
- /// Parent object
- /// Texture object name
StreamingTexture(ITextureOwner* owner, const String& name);
-
- ///
- /// Destructor
- ///
~StreamingTexture();
public:
@@ -42,31 +31,23 @@ public:
///
/// Gets the owner.
///
- /// The owner.
FORCE_INLINE ITextureOwner* GetOwner() const
{
return _owner;
}
///
- /// Gets texture object handle
+ /// Gets texture object handle.
///
- /// Texture object
FORCE_INLINE GPUTexture* GetTexture() const
{
return _texture;
}
///
- /// Gets texture size of Vector2::Zero if not loaded
+ /// Gets texture size of Vector2::Zero if not loaded.
///
- /// Texture size
- FORCE_INLINE Vector2 Size() const
- {
- return _texture->Size();
- }
-
-public:
+ Vector2 Size() const;
///
/// Gets a value indicating whether this instance is initialized.
@@ -88,7 +69,6 @@ public:
///
/// Gets total texture height (in texels)
///
- /// Texture width
FORCE_INLINE int32 TotalHeight() const
{
return _header.Height;
@@ -97,7 +77,6 @@ public:
///
/// Gets total texture array size
///
- /// Texture array size
FORCE_INLINE int32 TotalArraySize() const
{
return IsCubeMap() ? 6 : 1;
@@ -106,7 +85,6 @@ public:
///
/// Gets total texture mip levels count
///
- /// Texture mip levels
FORCE_INLINE int32 TotalMipLevels() const
{
return _header.MipLevels;
@@ -115,7 +93,6 @@ public:
///
/// Returns texture format type
///
- /// Texture format type
FORCE_INLINE TextureFormatType GetFormatType() const
{
return _header.Type;
@@ -124,7 +101,6 @@ public:
///
/// Returns true if it's a cube map texture
///
- /// True if i's a cubemap
FORCE_INLINE bool IsCubeMap() const
{
return _header.IsCubeMap;
@@ -133,7 +109,6 @@ public:
///
/// Returns true if texture cannot be used during GPU resources streaming system
///
- /// True if texture cannot be used during GPU resources streaming system
FORCE_INLINE bool NeverStream() const
{
return _header.NeverStream;
@@ -142,7 +117,6 @@ public:
///
/// Gets the texture header.
///
- /// Header
FORCE_INLINE const TextureHeader* GetHeader() const
{
return &_header;
@@ -163,22 +137,14 @@ public:
///
/// Index of the texture mip.
/// The index of the mip map.
- FORCE_INLINE int32 TextureMipIndexToTotalIndex(int32 textureMipIndex) const
- {
- const int32 missingMips = TotalMipLevels() - _texture->MipLevels();
- return textureMipIndex + missingMips;
- }
+ int32 TextureMipIndexToTotalIndex(int32 textureMipIndex) const;
///
/// Converts absolute mip map index to the allocated texture mip index.
///
/// Index of the texture mip.
/// The index of the mip map.
- FORCE_INLINE int32 TotalIndexToTextureMipIndex(int32 mipIndex) const
- {
- const int32 missingMips = TotalMipLevels() - _texture->MipLevels();
- return mipIndex - missingMips;
- }
+ int32 TotalIndexToTextureMipIndex(int32 mipIndex) const;
public:
@@ -211,27 +177,15 @@ public:
public:
// [Object]
- String ToString() const override
- {
- return _texture->ToString();
- }
+ String ToString() const override;
// [StreamableResource]
int32 GetMaxResidency() const override
{
return _header.MipLevels;
}
-
- int32 GetCurrentResidency() const override
- {
- return _texture->ResidentMipLevels();
- }
-
- int32 GetAllocatedResidency() const override
- {
- return _texture->MipLevels();
- }
-
+ int32 GetCurrentResidency() const override;
+ int32 GetAllocatedResidency() const override;
bool CanBeUpdated() const override;
Task* UpdateAllocation(int32 residency) override;
Task* CreateStreamingTask(int32 residency) override;
diff --git a/Source/Engine/Graphics/Textures/TextureBase.cpp b/Source/Engine/Graphics/Textures/TextureBase.cpp
index 83e781a5a..d21d61f2f 100644
--- a/Source/Engine/Graphics/Textures/TextureBase.cpp
+++ b/Source/Engine/Graphics/Textures/TextureBase.cpp
@@ -3,10 +3,11 @@
#include "TextureBase.h"
#include "TextureData.h"
#include "Engine/Graphics/GPUDevice.h"
-#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
-#include "Engine/Debug/Exceptions/InvalidOperationException.h"
+#include "Engine/Graphics/Textures/GPUTexture.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Graphics/PixelFormatExtensions.h"
+#include "Engine/Debug/Exceptions/ArgumentOutOfRangeException.h"
+#include "Engine/Debug/Exceptions/InvalidOperationException.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Content/Factories/BinaryAssetFactory.h"
@@ -22,6 +23,36 @@ TextureBase::TextureBase(const SpawnParams& params, const AssetInfo* info)
{
}
+Vector2 TextureBase::Size() const
+{
+ return Vector2(static_cast(_texture.TotalWidth()), static_cast(_texture.TotalHeight()));
+}
+
+int32 TextureBase::GetArraySize() const
+{
+ return StreamingTexture()->TotalArraySize();
+}
+
+int32 TextureBase::GetMipLevels() const
+{
+ return StreamingTexture()->TotalMipLevels();
+}
+
+int32 TextureBase::GetResidentMipLevels() const
+{
+ return GetTexture()->ResidentMipLevels();
+}
+
+uint64 TextureBase::GetCurrentMemoryUsage() const
+{
+ return GetTexture()->GetMemoryUsage();
+}
+
+uint64 TextureBase::GetTotalMemoryUsage() const
+{
+ return StreamingTexture()->GetTotalMemoryUsage();
+}
+
BytesContainer TextureBase::GetMipData(int32 mipIndex, int32& rowPitch, int32& slicePitch)
{
BytesContainer result;
@@ -193,9 +224,9 @@ int32 TextureBase::calculateChunkIndex(int32 mipIndex) const
return mipIndex;
}
-CriticalSection* TextureBase::GetOwnerLocker() const
+CriticalSection& TextureBase::GetOwnerLocker() const
{
- return &_parent->Locker;
+ return _parent->Locker;
}
void TextureBase::unload(bool isReloading)
diff --git a/Source/Engine/Graphics/Textures/TextureBase.h b/Source/Engine/Graphics/Textures/TextureBase.h
index 2cb895a23..7839f940a 100644
--- a/Source/Engine/Graphics/Textures/TextureBase.h
+++ b/Source/Engine/Graphics/Textures/TextureBase.h
@@ -6,6 +6,8 @@
#include "StreamingTexture.h"
#include "Engine/Core/Log.h"
+class TextureData;
+
///
/// Base class for , , and other assets that can contain texture data.
///
@@ -103,50 +105,32 @@ public:
///
/// Gets the total size of the texture. Actual resident size may be different due to dynamic content streaming. Returns Vector2::Zero if texture is not loaded.
///
- API_PROPERTY() FORCE_INLINE Vector2 Size() const
- {
- return Vector2(static_cast(_texture.TotalWidth()), static_cast(_texture.TotalHeight()));
- }
+ API_PROPERTY() Vector2 Size() const;
///
/// Gets the total array size of the texture.
///
- API_PROPERTY() int32 GetArraySize() const
- {
- return StreamingTexture()->TotalArraySize();
- }
+ API_PROPERTY() int32 GetArraySize() const;
///
/// Gets the total mip levels count of the texture. Actual resident mipmaps count may be different due to dynamic content streaming.
///
- API_PROPERTY() int32 GetMipLevels() const
- {
- return StreamingTexture()->TotalMipLevels();
- }
+ API_PROPERTY() int32 GetMipLevels() const;
///
/// Gets the current mip levels count of the texture that are on GPU ready to use.
///
- API_PROPERTY() int32 GetResidentMipLevels() const
- {
- return GetTexture()->ResidentMipLevels();
- }
+ API_PROPERTY() int32 GetResidentMipLevels() const;
///
/// Gets the amount of the memory used by this resource. Exact value may differ due to memory alignment and resource allocation policy.
///
- API_PROPERTY() uint64 GetCurrentMemoryUsage() const
- {
- return GetTexture()->GetMemoryUsage();
- }
+ API_PROPERTY() uint64 GetCurrentMemoryUsage() const;
///
/// Gets the total memory usage that texture may have in use (if loaded to the maximum quality). Exact value may differ due to memory alignment and resource allocation policy.
///
- API_PROPERTY() uint64 GetTotalMemoryUsage() const
- {
- return StreamingTexture()->GetTotalMemoryUsage();
- }
+ API_PROPERTY() uint64 GetTotalMemoryUsage() const;
public:
@@ -186,7 +170,7 @@ private:
public:
// [ITextureOwner]
- CriticalSection* GetOwnerLocker() const override;
+ CriticalSection& GetOwnerLocker() const override;
Task* RequestMipDataAsync(int32 mipIndex) override;
FlaxStorage::LockData LockData() override;
void GetMipData(int32 mipIndex, BytesContainer& data) const override;
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
index 1cd90b11b..2acd2712c 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUBufferVulkan.cpp
@@ -17,14 +17,17 @@ void GPUBufferViewVulkan::Init(GPUDeviceVulkan* device, GPUBufferVulkan* owner,
Buffer = buffer;
Size = size;
- VkBufferViewCreateInfo viewInfo;
- RenderToolsVulkan::ZeroStruct(viewInfo, VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO);
- viewInfo.buffer = Buffer;
- viewInfo.format = RenderToolsVulkan::ToVulkanFormat(format);
- viewInfo.offset = 0;
- viewInfo.range = Size;
-
- VALIDATE_VULKAN_RESULT(vkCreateBufferView(device->Device, &viewInfo, nullptr, &View));
+ if (owner->IsShaderResource() && !(owner->GetDescription().Flags & GPUBufferFlags::Structured))
+ {
+ VkBufferViewCreateInfo viewInfo;
+ RenderToolsVulkan::ZeroStruct(viewInfo, VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO);
+ viewInfo.buffer = Buffer;
+ viewInfo.format = RenderToolsVulkan::ToVulkanFormat(format);
+ viewInfo.offset = 0;
+ viewInfo.range = Size;
+ ASSERT_LOW_LAYER(viewInfo.format != VK_FORMAT_UNDEFINED);
+ VALIDATE_VULKAN_RESULT(vkCreateBufferView(device->Device, &viewInfo, nullptr, &View));
+ }
}
void GPUBufferViewVulkan::Release()
@@ -32,19 +35,18 @@ void GPUBufferViewVulkan::Release()
if (View != VK_NULL_HANDLE)
{
Device->DeferredDeletionQueue.EnqueueResource(DeferredDeletionQueueVulkan::BufferView, View);
-
View = VK_NULL_HANDLE;
-
-#if BUILD_DEBUG
- Device = nullptr;
- Owner = nullptr;
- Buffer = VK_NULL_HANDLE;
-#endif
}
+#if BUILD_DEBUG
+ Device = nullptr;
+ Owner = nullptr;
+ Buffer = VK_NULL_HANDLE;
+#endif
}
void GPUBufferViewVulkan::DescriptorAsUniformTexelBuffer(GPUContextVulkan* context, const VkBufferView*& bufferView)
{
+ ASSERT_LOW_LAYER(View != VK_NULL_HANDLE);
bufferView = &View;
context->AddBufferBarrier(Owner, VK_ACCESS_SHADER_READ_BIT);
@@ -52,6 +54,7 @@ void GPUBufferViewVulkan::DescriptorAsUniformTexelBuffer(GPUContextVulkan* conte
void GPUBufferViewVulkan::DescriptorAsStorageBuffer(GPUContextVulkan* context, VkBuffer& buffer, VkDeviceSize& offset, VkDeviceSize& range)
{
+ ASSERT_LOW_LAYER(Buffer);
buffer = Buffer;
offset = 0;
range = Size;
@@ -88,7 +91,7 @@ bool GPUBufferVulkan::OnInit()
bufferInfo.size = _desc.Size;
bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT;
- if (useSRV)
+ if (useSRV && !(_desc.Flags & GPUBufferFlags::Structured))
bufferInfo.usage |= VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT;
if (useUAV || _desc.Flags & GPUBufferFlags::RawBuffer)
bufferInfo.usage |= VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
@@ -165,7 +168,7 @@ bool GPUBufferVulkan::OnInit()
}
}
// Check if need to bind buffer to the shaders
- else if (useSRV)
+ else if (useSRV || useUAV)
{
// Create buffer view
_view.Init(_device, this, _buffer, _desc.Size, _desc.Format);
diff --git a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
index e05ab111b..6f1c4a8de 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
+++ b/Source/Engine/GraphicsDevice/Vulkan/GPUDeviceVulkan.cpp
@@ -27,6 +27,7 @@
#include "Engine/Core/Utilities.h"
#include "Engine/Core/Math/Color32.h"
#include "Engine/Engine/Engine.h"
+#include "Engine/Engine/Globals.h"
#include "Engine/Engine/CommandLine.h"
#include "Engine/Utilities/StringConverter.h"
#include "Engine/Profiler/ProfilerCPU.h"
@@ -144,8 +145,8 @@ static VKAPI_ATTR VkBool32 VKAPI_PTR DebugUtilsCallback(VkDebugUtilsMessageSever
case 2: // Fragment shader writes to output location 0 with no matching attachment
case 3: // Attachment 2 not written by fragment shader
case 5: // SPIR-V module not valid: MemoryBarrier: Vulkan specification requires Memory Semantics to have one of the following bits set: Acquire, Release, AcquireRelease or SequentiallyConsistent
-#if PLATFORM_ANDROID
case -1666394502: // After query pool creation, each query must be reset before it is used. Queries must also be reset between uses.
+#if PLATFORM_ANDROID
case 602160055: // Attachment 4 not written by fragment shader; undefined values will be written to attachment. TODO: investigate it for PS_GBuffer shader from Deferred material with USE_LIGHTMAP=1
#endif
return VK_FALSE;
@@ -352,7 +353,7 @@ DeferredDeletionQueueVulkan::~DeferredDeletionQueueVulkan()
void DeferredDeletionQueueVulkan::ReleaseResources(bool deleteImmediately)
{
- ScopeLock lock(&_locker);
+ ScopeLock lock(_locker);
const uint64 checkFrame = Engine::FrameCount - VULKAN_RESOURCE_DELETE_SAFE_FRAMES_COUNT;
for (int32 i = 0; i < _entries.Count(); i++)
{
diff --git a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
index cf9b7e9cf..ec5d882bc 100644
--- a/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
+++ b/Source/Engine/GraphicsDevice/Vulkan/RenderToolsVulkan.h
@@ -78,6 +78,9 @@ public:
case 0:
stageFlags = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
break;
+ case VK_ACCESS_INDIRECT_COMMAND_READ_BIT:
+ stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
+ break;
case VK_ACCESS_TRANSFER_WRITE_BIT:
stageFlags = VK_PIPELINE_STAGE_TRANSFER_BIT;
break;
diff --git a/Source/Engine/Input/InputDevice.h b/Source/Engine/Input/InputDevice.h
index 81b4eceb7..27f6125ba 100644
--- a/Source/Engine/Input/InputDevice.h
+++ b/Source/Engine/Input/InputDevice.h
@@ -113,7 +113,7 @@ public:
/// Captures the input since the last call and triggers the input events.
///
/// The input events queue.
- /// True if device has been disconnected, otherwise false.
+ /// True if device has been disconnected, otherwise false.
virtual bool Update(EventQueue& queue)
{
if (UpdateState())
@@ -126,7 +126,7 @@ public:
///
/// Updates only the current state of the device.
///
- /// True if device has been disconnected, otherwise false.
+ /// True if device has been disconnected, otherwise false.
virtual bool UpdateState()
{
return false;
diff --git a/Source/Engine/Input/InputSettings.h b/Source/Engine/Input/InputSettings.h
index 7771028e8..fd594f3ee 100644
--- a/Source/Engine/Input/InputSettings.h
+++ b/Source/Engine/Input/InputSettings.h
@@ -5,6 +5,7 @@
#include "Engine/Core/Config/Settings.h"
#include "Engine/Serialization/JsonTools.h"
#include "VirtualInput.h"
+#include "Engine/Core/Collections/Array.h"
///
/// Input settings container.
diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp
index ef5b2a554..20ec4cb7a 100644
--- a/Source/Engine/Level/Actor.cpp
+++ b/Source/Engine/Level/Actor.cpp
@@ -15,7 +15,9 @@
#include "Engine/Core/Cache.h"
#include "Engine/Core/Collections/CollectionPoolCache.h"
#include "Engine/Debug/Exceptions/JsonParseException.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderView.h"
+#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Serialization/ISerializeModifier.h"
#include "Engine/Serialization/Serialization.h"
@@ -1246,12 +1248,6 @@ void Actor::OnDebugDraw()
for (auto* script : Scripts)
if (script->GetEnabled())
script->OnDebugDraw();
-
- for (auto& child : Children)
- {
- if (child->GetIsActive())
- child->OnDebugDraw();
- }
}
void Actor::OnDebugDrawSelected()
@@ -1494,6 +1490,7 @@ void WriteObjectToBytes(SceneObject* obj, rapidjson_flax::StringBuffer& buffer,
bool Actor::ToBytes(const Array& actors, MemoryWriteStream& output)
{
+ PROFILE_CPU();
if (actors.IsEmpty())
{
// Cannot serialize empty list
@@ -1553,6 +1550,7 @@ Array Actor::ToBytes(const Array& actors)
bool Actor::FromBytes(const Span& data, Array& output, ISerializeModifier* modifier)
{
+ PROFILE_CPU();
output.Clear();
ASSERT(modifier);
@@ -1597,7 +1595,7 @@ bool Actor::FromBytes(const Span& data, Array& output, ISerializeM
// Order in parent
int32 orderInParent;
stream.ReadInt32(&orderInParent);
- order.At(i) = orderInParent;
+ order[i] = orderInParent;
// Load JSON
rapidjson_flax::Document document;
@@ -1637,7 +1635,6 @@ bool Actor::FromBytes(const Span& data, Array& output, ISerializeM
// Order in parent
int32 orderInParent;
stream.ReadInt32(&orderInParent);
- order.Add(orderInParent);
// Load JSON
rapidjson_flax::Document document;
@@ -1655,17 +1652,19 @@ bool Actor::FromBytes(const Span& data, Array& output, ISerializeM
Scripting::ObjectsLookupIdMapping.Set(nullptr);
// Link objects
- for (int32 i = 0; i < objectsCount; i++)
+ //for (int32 i = 0; i < objectsCount; i++)
{
- SceneObject* obj = sceneObjects->At(i);
- obj->PostLoad();
+ //SceneObject* obj = sceneObjects->At(i);
+ // TODO: post load or post spawn?
+ //obj->PostLoad();
}
// Update objects order
- for (int32 i = 0; i < objectsCount; i++)
+ //for (int32 i = 0; i < objectsCount; i++)
{
- SceneObject* obj = sceneObjects->At(i);
- obj->SetOrderInParent(order[i]);
+ //SceneObject* obj = sceneObjects->At(i);
+ // TODO: remove order from saved data?
+ //obj->SetOrderInParent(order[i]);
}
// Call events (only for parents because they will propagate events down the tree)
@@ -1682,6 +1681,10 @@ bool Actor::FromBytes(const Span& data, Array& output, ISerializeM
}
}
for (int32 i = 0; i < parents->Count(); i++)
+ {
+ parents->At(i)->PostSpawn();
+ }
+ for (int32 i = 0; i < parents->Count(); i++)
{
Actor* actor = parents->At(i);
actor->OnTransformChanged();
@@ -1723,6 +1726,7 @@ Array Actor::FromBytes(const Span& data, const Dictionary Actor::TryGetSerializedObjectsIds(const Span& data)
{
+ PROFILE_CPU();
Array result;
if (data.Length() > 0)
{
@@ -1743,6 +1747,7 @@ Array Actor::TryGetSerializedObjectsIds(const Span& data)
String Actor::ToJson()
{
+ PROFILE_CPU();
rapidjson_flax::StringBuffer buffer;
CompactJsonWriter writer(buffer);
writer.SceneObject(this);
@@ -1754,6 +1759,8 @@ String Actor::ToJson()
void Actor::FromJson(const StringAnsiView& json)
{
+ PROFILE_CPU();
+
// Load JSON
rapidjson_flax::Document document;
document.Parse(json.Get(), json.Length());
diff --git a/Source/Engine/Level/Actor.cs b/Source/Engine/Level/Actor.cs
index 2d9c27b9a..fce009549 100644
--- a/Source/Engine/Level/Actor.cs
+++ b/Source/Engine/Level/Actor.cs
@@ -124,7 +124,7 @@ namespace FlaxEngine
public Actor AddChild(Type type)
{
var result = (Actor)New(type);
- result.SetParent(this, false);
+ result.SetParent(this, false, false);
return result;
}
@@ -136,7 +136,7 @@ namespace FlaxEngine
public T AddChild() where T : Actor
{
var result = New();
- result.SetParent(this, false);
+ result.SetParent(this, false, false);
return result;
}
@@ -173,7 +173,7 @@ namespace FlaxEngine
if (result == null)
{
result = New();
- result.SetParent(this, false);
+ result.SetParent(this, false, false);
}
return result;
}
diff --git a/Source/Engine/Level/Actor.h b/Source/Engine/Level/Actor.h
index 560403890..00aeb17ab 100644
--- a/Source/Engine/Level/Actor.h
+++ b/Source/Engine/Level/Actor.h
@@ -176,7 +176,7 @@ public:
/// New parent
/// Should actor world positions remain the same after parent change?
/// True if can break prefab link on changing the parent.
- void SetParent(Actor* value, bool worldPositionsStays, bool canBreakPrefabLink);
+ API_FUNCTION() void SetParent(Actor* value, bool worldPositionsStays, bool canBreakPrefabLink);
///
/// Gets amount of child actors.
@@ -665,12 +665,12 @@ public:
#if USE_EDITOR
///
- /// Draws debug shapes for the actor and all child actors.
+ /// Draws debug shapes for the actor and all child scripts.
///
virtual void OnDebugDraw();
///
- /// Draws debug shapes for the selected actor and all child actors.
+ /// Draws debug shapes for the selected actor and all child scripts.
///
virtual void OnDebugDrawSelected();
diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp
index f0ae7017e..a62aad592 100644
--- a/Source/Engine/Level/Actors/AnimatedModel.cpp
+++ b/Source/Engine/Level/Actors/AnimatedModel.cpp
@@ -8,10 +8,13 @@
#include "Editor/Editor.h"
#endif
#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Level/Scene/Scene.h"
#include "Engine/Level/SceneObjectsFactory.h"
#include "Engine/Serialization/Serialization.h"
+extern Array UpdateBones;
+
AnimatedModel::AnimatedModel(const SpawnParams& params)
: ModelInstanceActor(params)
, _actualMode(AnimationUpdateMode::Never)
@@ -41,7 +44,8 @@ void AnimatedModel::UpdateAnimation()
|| !IsActiveInHierarchy()
|| SkinnedModel == nullptr
|| !SkinnedModel->IsLoaded()
- || _lastUpdateFrame == Engine::FrameCount)
+ || _lastUpdateFrame == Engine::FrameCount
+ || _masterPose)
return;
_lastUpdateFrame = Engine::FrameCount;
@@ -131,6 +135,22 @@ void AnimatedModel::GetCurrentPose(Array& nodesTransformation, bool worl
}
}
+void AnimatedModel::SetCurrentPose(const Array& nodesTransformation, bool worldSpace)
+{
+ if (GraphInstance.NodesPose.Count() == 0)
+ return;
+ CHECK(nodesTransformation.Count() == GraphInstance.NodesPose.Count());
+ GraphInstance.NodesPose = nodesTransformation;
+ if (worldSpace)
+ {
+ Matrix invWorld;
+ Matrix::Invert(_world, invWorld);
+ for (auto& m : GraphInstance.NodesPose)
+ m = invWorld * m;
+ }
+ OnAnimationUpdated();
+}
+
void AnimatedModel::GetNodeTransformation(int32 nodeIndex, Matrix& nodeTransformation, bool worldSpace) const
{
if (nodeIndex >= 0 && nodeIndex < GraphInstance.NodesPose.Count())
@@ -146,6 +166,35 @@ void AnimatedModel::GetNodeTransformation(const StringView& nodeName, Matrix& no
GetNodeTransformation(SkinnedModel ? SkinnedModel->FindNode(nodeName) : -1, nodeTransformation, worldSpace);
}
+int32 AnimatedModel::FindClosestNode(const Vector3& location, bool worldSpace) const
+{
+ const Vector3 pos = worldSpace ? _transform.WorldToLocal(location) : location;
+ int32 result = -1;
+ float closest = MAX_float;
+ for (int32 nodeIndex = 0; nodeIndex < GraphInstance.NodesPose.Count(); nodeIndex++)
+ {
+ const Vector3 node = GraphInstance.NodesPose[nodeIndex].GetTranslation();
+ const float dst = Vector3::DistanceSquared(node, pos);
+ if (dst < closest)
+ {
+ closest = dst;
+ result = nodeIndex;
+ }
+ }
+ return result;
+}
+
+void AnimatedModel::SetMasterPoseModel(AnimatedModel* masterPose)
+{
+ if (masterPose == _masterPose)
+ return;
+ if (_masterPose)
+ _masterPose->AnimationUpdated.Unbind(this);
+ _masterPose = masterPose;
+ if (_masterPose)
+ _masterPose->AnimationUpdated.Bind(this);
+}
+
#define CHECK_ANIM_GRAPH_PARAM_ACCESS() \
if (!AnimationGraph) \
{ \
@@ -233,6 +282,8 @@ void AnimatedModel::SetParameterValue(const Guid& id, const Variant& value)
LOG(Warning, "Failed to set animated model '{0}' missing parameter '{1}'", ToString(), id.ToString());
}
+#undef CHECK_ANIM_GRAPH_PARAM_ACCESS
+
float AnimatedModel::GetBlendShapeWeight(const StringView& name)
{
for (auto& e : _blendShapes.Weights)
@@ -339,6 +390,7 @@ void AnimatedModel::BeginPlay(SceneBeginData* data)
void AnimatedModel::EndPlay()
{
AnimationManager::RemoveFromUpdate(this);
+ SetMasterPoseModel(nullptr);
// Base
ModelInstanceActor::EndPlay();
@@ -401,12 +453,38 @@ void AnimatedModel::UpdateBounds()
BoundingSphere::FromBox(_box, _sphere);
}
-void AnimatedModel::OnAnimUpdate()
+void AnimatedModel::OnAnimationUpdated()
{
+ ANIM_GRAPH_PROFILE_EVENT("OnAnimationUpdated");
+ auto& skeleton = SkinnedModel->Skeleton;
+
+ // Copy pose from the master
+ if (_masterPose && _masterPose->SkinnedModel->Skeleton.Nodes.Count() == skeleton.Nodes.Count())
+ {
+ ANIM_GRAPH_PROFILE_EVENT("Copy Master Pose");
+ const auto& masterInstance = _masterPose->GraphInstance;
+ GraphInstance.NodesPose = masterInstance.NodesPose;
+ GraphInstance.RootTransform = masterInstance.RootTransform;
+ GraphInstance.RootMotion = masterInstance.RootMotion;
+ }
+
+ // Calculate the final bones transformations and update skinning
+ {
+ ANIM_GRAPH_PROFILE_EVENT("Final Pose");
+ UpdateBones.Resize(skeleton.Bones.Count(), false);
+ for (int32 boneIndex = 0; boneIndex < skeleton.Bones.Count(); boneIndex++)
+ {
+ auto& bone = skeleton.Bones[boneIndex];
+ UpdateBones[boneIndex] = bone.OffsetMatrix * GraphInstance.NodesPose[bone.NodeIndex];
+ }
+ }
+ _skinningData.SetData(UpdateBones.Get(), !PerBoneMotionBlur);
+
UpdateBounds();
UpdateSockets();
ApplyRootMotion(GraphInstance.RootMotion);
_blendShapes.Update(SkinnedModel.Get());
+ AnimationUpdated();
}
void AnimatedModel::OnSkinnedModelChanged()
diff --git a/Source/Engine/Level/Actors/AnimatedModel.h b/Source/Engine/Level/Actors/AnimatedModel.h
index d5d9b4424..df218b897 100644
--- a/Source/Engine/Level/Actors/AnimatedModel.h
+++ b/Source/Engine/Level/Actors/AnimatedModel.h
@@ -6,6 +6,8 @@
#include "Engine/Content/Assets/SkinnedModel.h"
#include "Engine/Content/Assets/AnimationGraph.h"
#include "Engine/Graphics/Models/SkinnedMeshDrawData.h"
+#include "Engine/Renderer/DrawCall.h"
+#include "Engine/Core/Delegate.h"
///
/// Performs an animation and renders a skinned model.
@@ -63,6 +65,7 @@ private:
float _lastMinDstSqr;
uint64 _lastUpdateFrame;
BlendShapesInstance _blendShapes;
+ ScriptingObjectReference _masterPose;
public:
@@ -165,9 +168,14 @@ public:
API_FUNCTION() void ResetAnimation();
///
- /// Performs the full animation update.
+ /// Performs the full animation update. The actual update will be performed during gameplay tick.
///
API_FUNCTION() void UpdateAnimation();
+
+ ///
+ /// Called after animation gets updated (new skeleton pose).
+ ///
+ API_EVENT() Action AnimationUpdated;
///
/// Validates and creates a proper skinning data.
@@ -180,17 +188,19 @@ public:
API_FUNCTION() void PreInitSkinningData();
///
- /// Updates the child bone socket actors.
- ///
- API_FUNCTION() void UpdateSockets();
-
- ///
- /// Gets the per-node final transformations.
+ /// Gets the per-node final transformations (skeleton pose).
///
/// The output per-node final transformation matrices.
/// True if convert matrices into world-space, otherwise returned values will be in local-space of the actor.
API_FUNCTION() void GetCurrentPose(API_PARAM(Out) Array& nodesTransformation, bool worldSpace = false) const;
+ ///
+ /// Sets the per-node final transformations (skeleton pose).
+ ///
+ /// The per-node final transformation matrices.
+ /// True if convert matrices from world-space, otherwise values are in local-space of the actor.
+ API_FUNCTION() void SetCurrentPose(const Array& nodesTransformation, bool worldSpace = false);
+
///
/// Gets the node final transformation.
///
@@ -207,6 +217,20 @@ public:
/// True if convert matrices into world-space, otherwise returned values will be in local-space of the actor.
API_FUNCTION() void GetNodeTransformation(const StringView& nodeName, API_PARAM(Out) Matrix& nodeTransformation, bool worldSpace = false) const;
+ ///
+ /// Finds the closest node to a given location.
+ ///
+ /// The text location (in local-space of the actor or world-space depending on ).
+ /// True if convert input location is in world-space, otherwise it's in local-space of the actor.
+ /// The zero-based index of the found node. Returns -1 if skeleton is missing.
+ API_FUNCTION() int32 FindClosestNode(const Vector3& location, bool worldSpace = false) const;
+
+ ///
+ /// Sets the master pose model that will be used to copy the skeleton nodes animation. Useful for modular characters.
+ ///
+ /// The master pose actor to use.
+ API_FUNCTION() void SetMasterPoseModel(AnimatedModel* masterPose);
+
public:
///
@@ -275,27 +299,14 @@ public:
private:
- ///
- /// Applies the root motion delta to the target actor.
- ///
void ApplyRootMotion(const RootMotionData& rootMotionDelta);
-
- ///
- /// Synchronizes the parameters collection (may lost existing params data on collection change detected).
- ///
void SyncParameters();
- ///
- /// Updates the local bounds of the actor.
- ///
+ void Update();
void UpdateLocalBounds();
-
void UpdateBounds();
-
- ///
- /// Called after animation graph update.
- ///
- void OnAnimUpdate();
+ void UpdateSockets();
+ void OnAnimationUpdated();
void OnSkinnedModelChanged();
void OnSkinnedModelLoaded();
@@ -303,8 +314,6 @@ private:
void OnGraphChanged();
void OnGraphLoaded();
- void Update();
-
public:
// [ModelInstanceActor]
diff --git a/Source/Engine/Level/Actors/Camera.cpp b/Source/Engine/Level/Actors/Camera.cpp
index c37e30607..1cc7ba53b 100644
--- a/Source/Engine/Level/Actors/Camera.cpp
+++ b/Source/Engine/Level/Actors/Camera.cpp
@@ -5,14 +5,16 @@
#include "Engine/Core/Math/Viewport.h"
#include "Engine/Content/Assets/Model.h"
#include "Engine/Content/Content.h"
-#include "Engine/Platform/Window.h"
#include "Engine/Serialization/Serialization.h"
-#include "Engine/Level/Scene/SceneRendering.h"
#if USE_EDITOR
#include "Editor/Editor.h"
#include "Editor/Managed/ManagedEditor.h"
+#include "Engine/Renderer/DrawCall.h"
+#include "Engine/Graphics/RenderTask.h"
+#include "Engine/Level/Scene/SceneRendering.h"
#else
#include "Engine/Engine/Engine.h"
+#include "Engine/Platform/Window.h"
#endif
Array Camera::Cameras;
diff --git a/Source/Engine/Level/Actors/EnvironmentProbe.cpp b/Source/Engine/Level/Actors/EnvironmentProbe.cpp
index 9a2bb08a8..d5939d722 100644
--- a/Source/Engine/Level/Actors/EnvironmentProbe.cpp
+++ b/Source/Engine/Level/Actors/EnvironmentProbe.cpp
@@ -3,6 +3,7 @@
#include "EnvironmentProbe.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Graphics/RenderView.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Renderer/ProbesRenderer.h"
diff --git a/Source/Engine/Level/Actors/Light.cpp b/Source/Engine/Level/Actors/Light.cpp
index 56e3368b0..9f80216c5 100644
--- a/Source/Engine/Level/Actors/Light.cpp
+++ b/Source/Engine/Level/Actors/Light.cpp
@@ -2,6 +2,9 @@
#include "Light.h"
#include "../Scene/Scene.h"
+#if USE_EDITOR
+#include "Engine/Graphics/RenderView.h"
+#endif
#include "Engine/Serialization/Serialization.h"
Light::Light(const SpawnParams& params)
diff --git a/Source/Engine/Level/Actors/Sky.cpp b/Source/Engine/Level/Actors/Sky.cpp
index 49f46e9b9..1e35c27f0 100644
--- a/Source/Engine/Level/Actors/Sky.cpp
+++ b/Source/Engine/Level/Actors/Sky.cpp
@@ -4,14 +4,17 @@
#include "DirectionalLight.h"
#include "Engine/Core/Math/Color.h"
#include "Engine/Content/Content.h"
-#include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Renderer/AtmospherePreCompute.h"
#include "Engine/Renderer/GBufferPass.h"
#include "Engine/Graphics/RenderBuffers.h"
+#include "Engine/Graphics/RenderView.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/GPUContext.h"
-#include "Engine/Serialization/Serialization.h"
+#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Graphics/Shaders/GPUConstantBuffer.h"
+#include "Engine/Graphics/Shaders/GPUShader.h"
+#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Scene/SceneRendering.h"
PACK_STRUCT(struct Data {
diff --git a/Source/Engine/Level/Actors/Sky.h b/Source/Engine/Level/Actors/Sky.h
index c5c81edc0..eafd8d9e6 100644
--- a/Source/Engine/Level/Actors/Sky.h
+++ b/Source/Engine/Level/Actors/Sky.h
@@ -9,6 +9,8 @@
#include "Engine/Renderer/Config.h"
#include "Engine/Renderer/DrawCall.h"
+class GPUPipelineState;
+
///
/// Sky actor renders atmosphere around the scene with fog and sky.
///
diff --git a/Source/Engine/Level/Actors/SkyLight.cpp b/Source/Engine/Level/Actors/SkyLight.cpp
index 03e1d3ca5..da7efbf31 100644
--- a/Source/Engine/Level/Actors/SkyLight.cpp
+++ b/Source/Engine/Level/Actors/SkyLight.cpp
@@ -3,6 +3,7 @@
#include "SkyLight.h"
#include "Engine/Platform/FileSystem.h"
#include "Engine/Graphics/RenderView.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/Textures/TextureData.h"
#include "Engine/Renderer/RenderList.h"
#include "Engine/Renderer/ProbesRenderer.h"
diff --git a/Source/Engine/Level/Actors/SplineModel.cpp b/Source/Engine/Level/Actors/SplineModel.cpp
index ffa995f58..3e874f07f 100644
--- a/Source/Engine/Level/Actors/SplineModel.cpp
+++ b/Source/Engine/Level/Actors/SplineModel.cpp
@@ -5,9 +5,14 @@
#include "Engine/Engine/Engine.h"
#include "Engine/Core/Math/Matrix3x4.h"
#include "Engine/Serialization/Serialization.h"
+#include "Engine/Graphics/GPUBufferDescription.h"
#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/GPUBuffer.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderTools.h"
#include "Engine/Profiler/ProfilerCPU.h"
+#include "Engine/Renderer/DrawCall.h"
+#include "Engine/Renderer/RenderList.h"
#if USE_EDITOR
#include "Editor/Editor.h"
#endif
diff --git a/Source/Engine/Level/Actors/StaticModel.cpp b/Source/Engine/Level/Actors/StaticModel.cpp
index 3f81b22c3..0005e74f9 100644
--- a/Source/Engine/Level/Actors/StaticModel.cpp
+++ b/Source/Engine/Level/Actors/StaticModel.cpp
@@ -2,7 +2,10 @@
#include "StaticModel.h"
#include "Engine/Engine/Engine.h"
+#include "Engine/Graphics/GPUBuffer.h"
+#include "Engine/Graphics/GPUBufferDescription.h"
#include "Engine/Graphics/GPUDevice.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Serialization/Serialization.h"
#include "Engine/Level/Prefabs/PrefabManager.h"
#include "Engine/Level/Scene/Scene.h"
diff --git a/Source/Engine/Level/Actors/StaticModel.h b/Source/Engine/Level/Actors/StaticModel.h
index a255ba4ab..b3276cc83 100644
--- a/Source/Engine/Level/Actors/StaticModel.h
+++ b/Source/Engine/Level/Actors/StaticModel.h
@@ -4,6 +4,7 @@
#include "ModelInstanceActor.h"
#include "Engine/Content/Assets/Model.h"
+#include "Engine/Renderer/DrawCall.h"
#include "Engine/Renderer/Lightmaps.h"
///
diff --git a/Source/Engine/Level/Level.cpp b/Source/Engine/Level/Level.cpp
index 613427d9f..efc73dc63 100644
--- a/Source/Engine/Level/Level.cpp
+++ b/Source/Engine/Level/Level.cpp
@@ -10,6 +10,7 @@
#include "Engine/Core/Collections/CollectionPoolCache.h"
#include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Core/Config/LayersTagsSettings.h"
+#include "Engine/Core/Types/LayersMask.h"
#include "Engine/Debug/Exceptions/ArgumentException.h"
#include "Engine/Debug/Exceptions/ArgumentNullException.h"
#include "Engine/Debug/Exceptions/InvalidOperationException.h"
@@ -202,7 +203,7 @@ void LayersAndTagsSettings::Apply()
void LevelService::Update()
{
- PROFILE_CPU();
+ PROFILE_CPU_NAMED("Level::Update");
ScopeLock lock(Level::ScenesLock);
auto& scenes = Level::Scenes;
@@ -231,7 +232,7 @@ void LevelService::Update()
void LevelService::LateUpdate()
{
- PROFILE_CPU();
+ PROFILE_CPU_NAMED("Level::LateUpdate");
ScopeLock lock(Level::ScenesLock);
auto& scenes = Level::Scenes;
@@ -263,7 +264,7 @@ void LevelService::LateUpdate()
void LevelService::FixedUpdate()
{
- PROFILE_CPU();
+ PROFILE_CPU_NAMED("Level::FixedUpdate");
ScopeLock lock(Level::ScenesLock);
auto& scenes = Level::Scenes;
@@ -642,7 +643,7 @@ public:
void LevelImpl::CallSceneEvent(SceneEventType eventType, Scene* scene, Guid sceneId)
{
- PROFILE_CPU();
+ PROFILE_CPU_NAMED("Level::CallSceneEvent");
// Call event
const auto scriptsDomain = Scripting::GetScriptsDomain();
diff --git a/Source/Engine/Level/Level.h b/Source/Engine/Level/Level.h
index 9fe9cb39b..1f7f0bb98 100644
--- a/Source/Engine/Level/Level.h
+++ b/Source/Engine/Level/Level.h
@@ -5,6 +5,7 @@
#include "Engine/Core/Delegate.h"
#include "Engine/Core/Types/DateTime.h"
#include "Engine/Core/Types/DataContainer.h"
+#include "Engine/Core/Collections/Array.h"
#include "Engine/Platform/CriticalSection.h"
#include "Engine/Scripting/ScriptingType.h"
#include "Engine/Serialization/JsonFwd.h"
diff --git a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp
index a6a0edd4b..abad0c275 100644
--- a/Source/Engine/Level/Prefabs/Prefab.Apply.cpp
+++ b/Source/Engine/Level/Prefabs/Prefab.Apply.cpp
@@ -6,6 +6,7 @@
#include "Engine/Core/ObjectsRemovalService.h"
#include "Engine/Core/Cache.h"
+#include "Engine/Core/Types/TimeSpan.h"
#include "Engine/Scripting/Scripting.h"
#include "Engine/Scripting/Script.h"
#include "Engine/Serialization/Json.h"
diff --git a/Source/Engine/Level/Prefabs/Prefab.cpp b/Source/Engine/Level/Prefabs/Prefab.cpp
index ed4ed2a2b..53bbb9d14 100644
--- a/Source/Engine/Level/Prefabs/Prefab.cpp
+++ b/Source/Engine/Level/Prefabs/Prefab.cpp
@@ -11,7 +11,7 @@
#include "Engine/Scripting/Scripting.h"
#endif
-REGISTER_JSON_ASSET(Prefab, "FlaxEngine.Prefab");
+REGISTER_JSON_ASSET(Prefab, "FlaxEngine.Prefab", false);
Prefab::Prefab(const SpawnParams& params, const AssetInfo* info)
: JsonAssetBase(params, info)
diff --git a/Source/Engine/Level/Prefabs/Prefab.h b/Source/Engine/Level/Prefabs/Prefab.h
index f5c25d273..694b50cdd 100644
--- a/Source/Engine/Level/Prefabs/Prefab.h
+++ b/Source/Engine/Level/Prefabs/Prefab.h
@@ -3,6 +3,7 @@
#pragma once
#include "Engine/Content/JsonAsset.h"
+#include "Engine/Core/Collections/Array.h"
#include "Engine/Core/Collections/Dictionary.h"
class Actor;
@@ -15,7 +16,6 @@ class SceneObject;
API_CLASS(NoSpawn) class FLAXENGINE_API Prefab : public JsonAssetBase
{
DECLARE_ASSET_HEADER(Prefab);
-
private:
bool _isCreatingDefaultInstance;
diff --git a/Source/Engine/Level/Scene/Lightmap.cpp b/Source/Engine/Level/Scene/Lightmap.cpp
index 4a2eec796..88fa88b5a 100644
--- a/Source/Engine/Level/Scene/Lightmap.cpp
+++ b/Source/Engine/Level/Scene/Lightmap.cpp
@@ -6,6 +6,7 @@
#include "Engine/Content/Content.h"
#include "Engine/Level/Level.h"
#include "Engine/Level/Scene/SceneLightmapsData.h"
+#include "Engine/Graphics/Textures/GPUTexture.h"
#if USE_EDITOR
#include "Engine/ContentImporters/ImportTexture.h"
#include "Engine/ContentImporters/AssetsImportingManager.h"
@@ -136,6 +137,14 @@ void Lightmap::EnsureSize(int32 size)
}
}
+bool Lightmap::IsReady() const
+{
+ // TODO: link for events and cache this to be a boolean value
+ return _textures[0] && _textures[0]->GetTexture()->ResidentMipLevels() > 0
+ && _textures[1] && _textures[1]->GetTexture()->ResidentMipLevels() > 0
+ && _textures[2] && _textures[2]->GetTexture()->ResidentMipLevels() > 0;
+}
+
#if USE_EDITOR
bool Lightmap::OnInitLightmap(TextureData& image)
diff --git a/Source/Engine/Level/Scene/Lightmap.h b/Source/Engine/Level/Scene/Lightmap.h
index c4550145d..6941f4323 100644
--- a/Source/Engine/Level/Scene/Lightmap.h
+++ b/Source/Engine/Level/Scene/Lightmap.h
@@ -96,14 +96,7 @@ public:
///
/// Determines whether this lightmap is ready (textures can be used by the renderer).
///
- /// True if lightmap textures are ready to use by renderer, otherwise false.
- FORCE_INLINE bool IsReady() const
- {
- // TODO: link for events and cache this to be a boolean value
- return _textures[0] && _textures[0]->GetTexture()->ResidentMipLevels() > 0
- && _textures[1] && _textures[1]->GetTexture()->ResidentMipLevels() > 0
- && _textures[2] && _textures[2]->GetTexture()->ResidentMipLevels() > 0;
- }
+ bool IsReady() const;
private:
diff --git a/Source/Engine/Level/Scene/Scene.cpp b/Source/Engine/Level/Scene/Scene.cpp
index 94de9d713..fb9b4ce50 100644
--- a/Source/Engine/Level/Scene/Scene.cpp
+++ b/Source/Engine/Level/Scene/Scene.cpp
@@ -13,8 +13,11 @@
#include "Engine/Navigation/NavMesh.h"
#include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Serialization/Serialization.h"
+#if USE_EDITOR
+#include "Engine/Engine/Globals.h"
+#endif
-REGISTER_JSON_ASSET(SceneAsset, "FlaxEngine.SceneAsset");
+REGISTER_JSON_ASSET(SceneAsset, "FlaxEngine.SceneAsset", false);
SceneAsset::SceneAsset(const SpawnParams& params, const AssetInfo* info)
: JsonAsset(params, info)
diff --git a/Source/Engine/Level/Scene/SceneRendering.cpp b/Source/Engine/Level/Scene/SceneRendering.cpp
index 0fb96b735..ce93b3e1c 100644
--- a/Source/Engine/Level/Scene/SceneRendering.cpp
+++ b/Source/Engine/Level/Scene/SceneRendering.cpp
@@ -2,6 +2,7 @@
#include "SceneRendering.h"
#include "Scene.h"
+#include "Engine/Graphics/RenderTask.h"
#include "Engine/Graphics/RenderView.h"
#include "Engine/Level/Actors/PostFxVolume.h"
diff --git a/Source/Engine/Level/Scene/SceneTicking.h b/Source/Engine/Level/Scene/SceneTicking.h
index 8962f1810..e8fbe8236 100644
--- a/Source/Engine/Level/Scene/SceneTicking.h
+++ b/Source/Engine/Level/Scene/SceneTicking.h
@@ -8,7 +8,7 @@
///
/// Scene gameplay updating helper subsystem that boosts the level ticking by providing efficient objects cache.
///
-class SceneTicking
+class FLAXENGINE_API SceneTicking
{
friend Scene;
@@ -17,7 +17,7 @@ public:
///
/// Tick function type.
///
- struct Tick
+ struct FLAXENGINE_API Tick
{
typedef void (*Signature)();
typedef void (*SignatureObj)(void*);
@@ -51,7 +51,7 @@ public:
}
};
- class TickData
+ class FLAXENGINE_API TickData
{
public:
@@ -144,7 +144,7 @@ public:
}
};
- class FixedUpdateTickData : public TickData
+ class FLAXENGINE_API FixedUpdateTickData : public TickData
{
public:
@@ -156,7 +156,7 @@ public:
void TickScripts(const Array