19 Commits

Author SHA1 Message Date
1f265bddf4 Fix XAudio2 DequeueProcessedBuffers
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
FlushSourceBuffers flushes all the pending buffers, not only just the
processed buffers.
2024-05-01 18:48:32 +03:00
3237849132 Fix looping audio sources not looping seamlessly 2024-05-01 18:48:31 +03:00
2be4d2b717 Optimize RichTextBox rendering with long text 2024-05-01 18:45:31 +03:00
dc3a1e142a Refactor native interop internal type lookup 2024-05-01 18:45:20 +03:00
b6d375e9a3 Move generated marshallers into separate namespace
Avoid polluting the `FlaxEngine` namespace with interop related
marshallers, move those to nested namespace called `Interop` where most
of the common marshallers are placed already.
2024-05-01 18:45:20 +03:00
495b6d6abc Include original type of the fields in blittable struct in comments 2024-05-01 18:45:20 +03:00
a49b398c7f Refactor struct custom marshalling generation 2024-05-01 18:45:20 +03:00
c8e893d2ec Fix assigning null values into value types in Custom Editor
Resets back to previous value instead of setting the editor value to
empty.
2024-05-01 18:44:58 +03:00
3a665199e7 Avoid deserializing clipboard content in Custom Editor paste checks 2024-05-01 18:44:58 +03:00
ca1aa89ba1 Update Editor options when window is shown 2024-05-01 18:44:27 +03:00
d92aaeb2b0 Fix Editor options data applying in realtime after first save
Reclone the data in order to not modify the currently applied options
data after save.
2024-05-01 18:44:27 +03:00
5f950cbb7e Store Debug Log view options in Editor options 2024-05-01 18:44:26 +03:00
8f613774cb Expose GPUTexture::DownloadData to Scripting API 2024-05-01 18:43:45 +03:00
c5c440469e Increase Editor profiler depth 2024-05-01 18:43:32 +03:00
1e6ed32c63 Update to enet 2.3.6 2024-05-01 18:43:31 +03:00
3ee6bffef7 Always run fixed update ticks at fixed deltatime
The random variance in fixed updates makes it impossible to do anything deterministic during physics ticks.
2024-05-01 18:43:31 +03:00
6105323ecc Update Transform component separately when applying Gizmo transform 2024-05-01 18:43:31 +03:00
23f8707927 Disable LFS override 2024-05-01 18:42:58 +03:00
761c8415dc Merge branch 'master' into signalgame
# Conflicts:
#	Flax.flaxproj
2024-05-01 18:42:14 +03:00
573 changed files with 9219 additions and 29043 deletions

View File

@@ -1,4 +1,4 @@
# Redirect to our own Git LFS server
[lfs]
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
locksverify = false
locksverify = false

BIN
Content/Editor/Camera/M_Camera.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/DefaultFontMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Gizmo/Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialWire.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/Highlight Material.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Icons/IconsMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/SpriteMaterial.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Editor/TexturePreviewMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Editor/Wires Debug Material.flax (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
Content/Engine/DefaultMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/DefaultTerrainMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SingleColorMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Engine/SkyboxMaterial.flax (Stored with Git LFS)

Binary file not shown.

BIN
Content/Shaders/Quad.flax (Stored with Git LFS)

Binary file not shown.

View File

@@ -14,8 +14,8 @@ call "Development\Scripts\Windows\CallBuildTool.bat" -genproject %*
if errorlevel 1 goto BuildToolFailed
:: Build bindings for all editor configurations
::echo Building C# bindings...
::Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
echo Building C# bindings...
Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor
popd
echo Done!

View File

@@ -1,5 +1,3 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using System.IO;
using FlaxEditor.Scripting;
@@ -96,8 +94,30 @@ public class AssetPickerValidator : IContentItemOwner
/// </summary>
public string SelectedPath
{
get => Utilities.Utils.ToPathProject(_selectedItem?.Path ?? _selected?.Path);
set => SelectedItem = string.IsNullOrEmpty(value) ? null : Editor.Instance.ContentDatabase.Find(Utilities.Utils.ToPathAbsolute(value));
get
{
string path = _selectedItem?.Path ?? _selected?.Path;
if (path != null)
{
// Convert into path relative to the project (cross-platform)
var projectFolder = Globals.ProjectFolder;
if (path.StartsWith(projectFolder))
path = path.Substring(projectFolder.Length + 1);
}
return path;
}
set
{
if (string.IsNullOrEmpty(value))
{
SelectedItem = null;
}
else
{
var path = StringUtils.IsRelative(value) ? Path.Combine(Globals.ProjectFolder, value) : value;
SelectedItem = Editor.Instance.ContentDatabase.Find(path);
}
}
}
/// <summary>
@@ -222,7 +242,7 @@ public class AssetPickerValidator : IContentItemOwner
/// <summary>
/// Initializes a new instance of the <see cref="AssetPickerValidator"/> class.
/// </summary>
/// <param name="assetType">The asset types that this picker accepts.</param>
/// <param name="assetType">The assets types that this picker accepts.</param>
public AssetPickerValidator(ScriptType assetType)
{
_type = assetType;

View File

@@ -1,28 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using FlaxEngine;
namespace FlaxEditor.Content
{
/// <summary>
/// Content item that contains video media file.
/// </summary>
/// <seealso cref="FlaxEditor.Content.JsonAssetItem" />
public sealed class VideoItem : FileItem
{
/// <summary>
/// Initializes a new instance of the <see cref="VideoItem"/> class.
/// </summary>
/// <param name="path">The file path.</param>
public VideoItem(string path)
: base(path)
{
}
/// <inheritdoc />
public override string TypeDescription => "Video";
/// <inheritdoc />
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.Document128;
}
}

View File

@@ -30,7 +30,9 @@ namespace FlaxEditor.Content
/// <summary>
/// Determines whether [is virtual proxy].
/// </summary>
/// <returns><c>true</c> if [is virtual proxy]; otherwise, <c>false</c>.</returns>
/// <returns>
/// <c>true</c> if [is virtual proxy]; otherwise, <c>false</c>.
/// </returns>
public bool IsVirtualProxy()
{
return IsVirtual && CanExport == false;

View File

@@ -29,12 +29,6 @@ namespace FlaxEditor.Content
return item is CSharpScriptItem;
}
/// <inheritdoc />
public override ContentItem ConstructItem(string path)
{
return new CSharpScriptItem(path);
}
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{

View File

@@ -39,16 +39,6 @@ namespace FlaxEditor.Content
return false;
}
/// <summary>
/// Constructs the item for the file.
/// </summary>
/// <param name="path">The file path.</param>
/// <returns>Created item or null.</returns>
public virtual ContentItem ConstructItem(string path)
{
return null;
}
/// <summary>
/// Gets a value indicating whether this proxy if for assets.
/// </summary>

View File

@@ -87,12 +87,6 @@ namespace FlaxEditor.Content
return item is CppScriptItem;
}
/// <inheritdoc />
public override ContentItem ConstructItem(string path)
{
return new CppScriptItem(path);
}
/// <inheritdoc />
protected override void GetTemplatePaths(out string headerTemplate, out string sourceTemplate)
{

View File

@@ -20,12 +20,6 @@ namespace FlaxEditor.Content
return item is FileItem;
}
/// <inheritdoc />
public override ContentItem ConstructItem(string path)
{
return new FileItem(path);
}
/// <inheritdoc />
public override string FileExtension => string.Empty;

View File

@@ -73,16 +73,6 @@ namespace FlaxEditor.Content
return targetLocation.CanHaveAssets;
}
/// <inheritdoc />
public override bool CanReimport(ContentItem item)
{
if (item is not PrefabItem prefabItem)
return base.CanReimport(item);
var prefab = FlaxEngine.Content.Load<Prefab>(prefabItem.ID);
return prefab.GetDefaultInstance().GetScript<ModelPrefab>() != null;
}
/// <inheritdoc />
public override void Create(string outputPath, object arg)
{

View File

@@ -1,48 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using FlaxEditor.Windows;
using FlaxEditor.Windows.Assets;
using FlaxEngine;
namespace FlaxEditor.Content
{
/// <summary>
/// A video media file proxy object.
/// </summary>
public class VideoProxy : ContentProxy
{
private readonly string _extension;
internal VideoProxy(string extension)
{
_extension = extension;
}
/// <inheritdoc />
public override string Name => "Video";
/// <inheritdoc />
public override string FileExtension => _extension;
/// <inheritdoc />
public override Color AccentColor => Color.FromRGB(0x11f7f1);
/// <inheritdoc />
public override bool IsProxyFor(ContentItem item)
{
return item is VideoItem;
}
/// <inheritdoc />
public override ContentItem ConstructItem(string path)
{
return new VideoItem(path);
}
/// <inheritdoc />
public override EditorWindow Open(Editor editor, ContentItem item)
{
return new VideoWindow(editor, (VideoItem)item);
}
}
}

View File

@@ -134,12 +134,6 @@ API_ENUM() enum class BuildPlatform
/// </summary>
API_ENUM(Attributes="EditorDisplay(null, \"iOS ARM64\")")
iOSARM64 = 14,
/// <summary>
/// Windows (ARM64)
/// </summary>
API_ENUM(Attributes = "EditorDisplay(null, \"Windows ARM64\")")
WindowsARM64 = 15,
};
/// <summary>
@@ -291,22 +285,24 @@ public:
/// <summary>
/// The total assets amount in the build.
/// </summary>
int32 TotalAssets = 0;
int32 TotalAssets;
/// <summary>
/// The cooked assets (TotalAssets - CookedAssets is amount of reused cached assets).
/// </summary>
int32 CookedAssets = 0;
int32 CookedAssets;
/// <summary>
/// The final output content size (in bytes).
/// The final output content size in MB.
/// </summary>
uint64 ContentSize = 0;
int32 ContentSizeMB;
/// <summary>
/// The asset type stats. Key is the asset typename, value is the stats container.
/// </summary>
Dictionary<String, AssetTypeStatistics> AssetStats;
Statistics();
};
/// <summary>
@@ -332,11 +328,6 @@ public:
/// </summary>
HashSet<Guid> Assets;
/// <summary>
/// The final files collection to include in build (valid only after CollectAssetsStep).
/// </summary>
HashSet<String> Files;
struct BinaryModuleInfo
{
String Name;

View File

@@ -148,8 +148,6 @@ const Char* ToString(const BuildPlatform platform)
return TEXT("Mac ARM64");
case BuildPlatform::iOSARM64:
return TEXT("iOS ARM64");
case BuildPlatform::WindowsARM64:
return TEXT("Windows ARM64");
default:
return TEXT("");
}
@@ -204,6 +202,13 @@ bool CookingData::AssetTypeStatistics::operator<(const AssetTypeStatistics& othe
return Count > other.Count;
}
CookingData::Statistics::Statistics()
{
TotalAssets = 0;
CookedAssets = 0;
ContentSizeMB = 0;
}
CookingData::CookingData(const SpawnParams& params)
: ScriptingObject(params)
{
@@ -302,10 +307,6 @@ void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& archi
platform = TEXT("iOS");
architecture = TEXT("ARM64");
break;
case BuildPlatform::WindowsARM64:
platform = TEXT("Windows");
architecture = TEXT("ARM64");
break;
default:
LOG(Fatal, "Unknown or unsupported build platform.");
}
@@ -392,9 +393,6 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
case BuildPlatform::Windows64:
result = New<WindowsPlatformTools>(ArchitectureType::x64);
break;
case BuildPlatform::WindowsARM64:
result = New<WindowsPlatformTools>(ArchitectureType::ARM64);
break;
#endif
#if PLATFORM_TOOLS_UWP
case BuildPlatform::UWPx86:
@@ -556,12 +554,7 @@ void GameCooker::GetCurrentPlatform(PlatformType& platform, BuildPlatform& build
switch (PLATFORM_TYPE)
{
case PlatformType::Windows:
if (PLATFORM_ARCH == ArchitectureType::x64)
buildPlatform = BuildPlatform::Windows64;
else if (PLATFORM_ARCH == ArchitectureType::ARM64)
buildPlatform = BuildPlatform::WindowsARM64;
else
buildPlatform = BuildPlatform::Windows32;
buildPlatform = PLATFORM_64BITS ? BuildPlatform::Windows64 : BuildPlatform::Windows32;
break;
case PlatformType::XboxOne:
buildPlatform = BuildPlatform::XboxOne;

View File

@@ -325,7 +325,9 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
const auto buildSettings = BuildSettings::Get();
if (buildSettings->SkipPackaging)
{
return false;
}
GameCooker::PackageFiles();
// Validate environment variables
@@ -363,7 +365,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
Platform::CreateProcess(procSettings);
}
#endif
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
const bool distributionPackage = buildSettings->ForDistribution;
{
CreateProcessSettings procSettings;
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));

View File

@@ -10,26 +10,47 @@
#include "Engine/Content/Assets/Shader.h"
#include "Engine/Content/Cache/AssetsCache.h"
bool CollectAssetsStep::Process(CookingData& data, Asset* asset)
{
// Skip virtual/temporary assets
if (asset->IsVirtual())
return false;
// Keep reference to the asset
AssetReference<Asset> ref(asset);
// Asset should have loaded data
if (asset->WaitForLoaded())
return false;
// Gather asset references
_references.Clear();
asset->Locker.Lock();
asset->GetReferences(_references);
asset->Locker.Unlock();
_assetsQueue.Add(_references);
return false;
}
bool CollectAssetsStep::Perform(CookingData& data)
{
LOG(Info, "Searching for assets to include in a build. Using {0} root assets.", data.RootAssets.Count());
data.StepProgress(TEXT("Collecting assets"), 0);
// Initialize assets queue
Array<Guid> assetsQueue;
assetsQueue.Clear();
assetsQueue.EnsureCapacity(1024);
_assetsQueue.Clear();
_assetsQueue.EnsureCapacity(1024);
for (auto i = data.RootAssets.Begin(); i.IsNotEnd(); ++i)
assetsQueue.Add(i->Item);
_assetsQueue.Add(i->Item);
// Iterate through the assets graph
AssetInfo assetInfo;
Array<Guid> references;
Array<String> files;
while (assetsQueue.HasItems())
while (_assetsQueue.HasItems())
{
BUILD_STEP_CANCEL_CHECK;
const Guid assetId = assetsQueue.Dequeue();
const auto assetId = _assetsQueue.Dequeue();
// Skip already processed or invalid assets
if (!assetId.IsValid()
@@ -48,31 +69,14 @@ bool CollectAssetsStep::Perform(CookingData& data)
}
// Load asset
AssetReference<Asset> asset = Content::LoadAsync<Asset>(assetId);
const auto asset = Content::LoadAsync<Asset>(assetId);
if (asset == nullptr)
continue;
// Process that asset
LOG_STR(Info, asset->GetPath());
data.Assets.Add(assetId);
// Skip virtual/temporary assets
if (asset->IsVirtual())
continue;
// Asset should have loaded data
if (asset->WaitForLoaded())
continue;
// Gather asset references
references.Clear();
asset->Locker.Lock();
asset->GetReferences(references, files);
asset->Locker.Unlock();
assetsQueue.Add(references);
for (String& file : files)
{
if (file.HasChars())
data.Files.Add(MoveTemp(file));
}
Process(data, asset);
}
data.Stats.TotalAssets = data.Assets.Count();

View File

@@ -12,7 +12,15 @@ class Asset;
/// <seealso cref="GameCooker::BuildStep" />
class CollectAssetsStep : public GameCooker::BuildStep
{
private:
Array<Guid> _assetsQueue;
Array<Guid> _references;
bool Process(CookingData& data, Asset* asset);
public:
// [BuildStep]
bool Perform(CookingData& data) override;
};

View File

@@ -447,7 +447,6 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
#if PLATFORM_TOOLS_WINDOWS
case BuildPlatform::Windows32:
case BuildPlatform::Windows64:
case BuildPlatform::WindowsARM64:
{
const char* platformDefineName = "PLATFORM_WINDOWS";
const auto settings = WindowsPlatformSettings::Get();
@@ -892,6 +891,7 @@ bool CookAssetsStep::Process(CookingData& data, CacheData& cache, JsonAssetBase*
class PackageBuilder : public NonCopyable
{
private:
int32 _packageIndex;
int32 MaxAssetsPerPackage;
int32 MaxPackageSize;
@@ -904,6 +904,7 @@ private:
uint64 packagesSizeTotal;
public:
/// <summary>
/// Initializes a new instance of the <see cref="PackageBuilder" /> class.
/// </summary>
@@ -932,6 +933,7 @@ public:
}
public:
uint64 GetPackagesSizeTotal() const
{
return packagesSizeTotal;
@@ -1040,11 +1042,8 @@ bool CookAssetsStep::Perform(CookingData& data)
float Step1ProgressEnd = 0.6f;
String Step1Info = TEXT("Cooking assets");
float Step2ProgressStart = Step1ProgressEnd;
float Step2ProgressEnd = 0.8f;
String Step2Info = TEXT("Cooking files");
float Step3ProgressStart = Step2ProgressStart;
float Step3ProgressEnd = 0.9f;
String Step3Info = TEXT("Packaging assets");
float Step2ProgressEnd = 0.9f;
String Step2Info = TEXT("Packaging assets");
data.StepProgress(TEXT("Loading build cache"), 0);
@@ -1101,14 +1100,11 @@ bool CookAssetsStep::Perform(CookingData& data)
#endif
int32 subStepIndex = 0;
AssetReference<Asset> assetRef;
assetRef.Unload.Bind([]
{
LOG(Error, "Asset got unloaded while cooking it!");
Platform::Sleep(100);
});
assetRef.Unload.Bind([]() { LOG(Error, "Asset gets unloaded while cooking it!"); Platform::Sleep(100); });
for (auto i = data.Assets.Begin(); i.IsNotEnd(); ++i)
{
BUILD_STEP_CANCEL_CHECK;
data.StepProgress(Step1Info, Math::Lerp(Step1ProgressStart, Step1ProgressEnd, static_cast<float>(subStepIndex++) / data.Assets.Count()));
const Guid assetId = i->Item;
@@ -1188,35 +1184,6 @@ bool CookAssetsStep::Perform(CookingData& data)
// Save build cache header
cache.Save(data);
// Process all files
for (auto i = data.Files.Begin(); i.IsNotEnd(); ++i)
{
BUILD_STEP_CANCEL_CHECK;
data.StepProgress(Step2Info, Math::Lerp(Step2ProgressStart, Step2ProgressEnd, (float)subStepIndex++ / data.Files.Count()));
const String& filePath = i->Item;
// Calculate destination path
String cookedPath = data.DataOutputPath;
if (FileSystem::IsRelative(filePath))
cookedPath /= filePath;
else
cookedPath /= String(TEXT("Content")) / StringUtils::GetFileName(filePath);
// Copy file
if (!FileSystem::FileExists(cookedPath) || FileSystem::GetFileLastEditTime(cookedPath) >= FileSystem::GetFileLastEditTime(filePath))
{
if (FileSystem::CreateDirectory(StringUtils::GetDirectoryName(cookedPath)))
return true;
if (FileSystem::CopyFile(cookedPath, filePath))
return true;
}
// Count stats of file extension
auto& assetStats = data.Stats.AssetStats[FileSystem::GetExtension(cookedPath)];
assetStats.Count++;
assetStats.ContentSize += FileSystem::GetFileSize(cookedPath);
}
// Create build game header
{
GameHeaderFlags gameFlags = GameHeaderFlags::None;
@@ -1262,11 +1229,13 @@ bool CookAssetsStep::Perform(CookingData& data)
for (auto i = AssetsRegistry.Begin(); i.IsNotEnd(); ++i)
{
BUILD_STEP_CANCEL_CHECK;
data.StepProgress(Step3Info, Math::Lerp(Step3ProgressStart, Step3ProgressEnd, (float)subStepIndex++ / AssetsRegistry.Count()));
data.StepProgress(Step2Info, Math::Lerp(Step2ProgressStart, Step2ProgressEnd, static_cast<float>(subStepIndex++) / AssetsRegistry.Count()));
const auto assetId = i->Key;
String cookedFilePath;
cache.GetFilePath(assetId, cookedFilePath);
if (!FileSystem::FileExists(cookedFilePath))
{
LOG(Warning, "Missing cooked file for asset \'{0}\'", assetId);
@@ -1284,12 +1253,12 @@ bool CookAssetsStep::Perform(CookingData& data)
return true;
for (auto& e : data.Stats.AssetStats)
e.Value.TypeName = e.Key;
data.Stats.ContentSize += packageBuilder.GetPackagesSizeTotal();
data.Stats.ContentSizeMB = static_cast<int32>(packageBuilder.GetPackagesSizeTotal() / (1024 * 1024));
}
BUILD_STEP_CANCEL_CHECK;
data.StepProgress(TEXT("Creating assets cache"), Step3ProgressEnd);
data.StepProgress(TEXT("Creating assets cache"), Step2ProgressEnd);
// Create asset paths mapping for the assets.
// Assets mapping is use to convert paths used in Content::Load(path) into the asset id.
@@ -1322,7 +1291,7 @@ bool CookAssetsStep::Perform(CookingData& data)
}
// Print stats
LOG(Info, "Cooked {0} assets, total assets: {1}, total content packages size: {2} MB", data.Stats.CookedAssets, AssetsRegistry.Count(), (int32)(data.Stats.ContentSize / (1024 * 1024)));
LOG(Info, "Cooked {0} assets, total assets: {1}, total content packages size: {2} MB", data.Stats.CookedAssets, AssetsRegistry.Count(), data.Stats.ContentSizeMB);
{
Array<CookingData::AssetTypeStatistics> assetTypes;
data.Stats.AssetStats.GetValues(assetTypes);

View File

@@ -73,7 +73,6 @@ bool DeployDataStep::Perform(CookingData& data)
{
case BuildPlatform::Windows32:
case BuildPlatform::Windows64:
case BuildPlatform::WindowsARM64:
canUseSystemDotnet = PLATFORM_TYPE == PlatformType::Windows;
break;
case BuildPlatform::LinuxX64:
@@ -160,20 +159,7 @@ bool DeployDataStep::Perform(CookingData& data)
}
else
{
// TODO: hostfxr for target platform should be copied from nuget package location: microsoft.netcore.app.runtime.<RID>/<VERSION>/runtimes/<RID>/native/hostfxr.dll
String dstHostfxr = dstDotnet / TEXT("host/fxr") / version;
if (!FileSystem::DirectoryExists(dstHostfxr))
FileSystem::CreateDirectory(dstHostfxr);
const Char *platformName, *archName;
data.GetBuildPlatformName(platformName, archName);
if (data.Platform == BuildPlatform::Windows64 || data.Platform == BuildPlatform::WindowsARM64 || data.Platform == BuildPlatform::Windows32)
failed |= FileSystem::CopyFile(dstHostfxr / TEXT("hostfxr.dll"), depsRoot / TEXT("ThirdParty") / archName / TEXT("hostfxr.dll"));
else if (data.Platform == BuildPlatform::LinuxX64)
failed |= FileSystem::CopyFile(dstHostfxr / TEXT("hostfxr.so"), depsRoot / TEXT("ThirdParty") / archName / TEXT("hostfxr.so"));
else if (data.Platform == BuildPlatform::MacOSx64 || data.Platform == BuildPlatform::MacOSARM64)
failed |= FileSystem::CopyFile(dstHostfxr / TEXT("hostfxr.dylib"), depsRoot / TEXT("ThirdParty") / archName / TEXT("hostfxr.dylib"));
else
failed |= true;
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("host/fxr") / version, srcDotnet / TEXT("host/fxr") / version, true);
failed |= EditorUtilities::CopyDirectoryIfNewer(dstDotnet / TEXT("shared/Microsoft.NETCore.App") / version, srcDotnet / TEXT("shared/Microsoft.NETCore.App") / version, true);
}
if (failed)

View File

@@ -663,7 +663,7 @@ namespace FlaxEditor.CustomEditors
}
}
if (obj == null || Values.Type.IsInstanceOfType(obj))
if ((obj == null && !Values.Type.IsValueType) || Values.Type.IsInstanceOfType(obj))
{
result = obj;
return true;
@@ -675,20 +675,7 @@ namespace FlaxEditor.CustomEditors
/// <summary>
/// Gets a value indicating whether can paste value from the system clipboard to the property value container.
/// </summary>
public bool CanPaste
{
get
{
try
{
return GetClipboardObject(out _, false);
}
catch
{
return false;
}
}
}
public bool CanPaste => !string.IsNullOrEmpty(Clipboard.Text);
/// <summary>
/// Sets the value from the system clipboard.

View File

@@ -52,18 +52,13 @@ namespace FlaxEditor.CustomEditors
// Check if use provided editor
if (overrideEditor != null)
return overrideEditor;
ScriptType targetType = values.Type;
// Special case if property is a pure object type and all values are the same type
if (targetType.Type == typeof(object) && values.Count > 0 && values[0] != null && !values.HasDifferentTypes)
if (values.Type.Type == typeof(object) && values.Count > 0 && values[0] != null && !values.HasDifferentTypes)
return CreateEditor(TypeUtils.GetObjectType(values[0]), canUseRefPicker);
// Special case if property is interface but the value is implemented as Scripting Object that should use reference picker
if (targetType.IsInterface && canUseRefPicker && values.Count > 0 && values[0] is FlaxEngine.Object)
return new DummyEditor();
// Use editor for the property type
return CreateEditor(targetType, canUseRefPicker);
return CreateEditor(values.Type, canUseRefPicker);
}
internal static CustomEditor CreateEditor(ScriptType targetType, bool canUseRefPicker = true)

View File

@@ -1,6 +1,5 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Content.Settings;
using FlaxEngine;
using FlaxEngine.GUI;
@@ -13,7 +12,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
[CustomEditor(typeof(LayersMask)), DefaultEditor]
internal class LayersMaskEditor : CustomEditor
{
private List<CheckBox> _checkBoxes;
private CheckBox[] _checkBoxes;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
@@ -25,18 +24,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
return;
}
_checkBoxes = new List<CheckBox>();
_checkBoxes = new CheckBox[layers.Length];
for (int i = 0; i < layers.Length; i++)
{
var layer = layers[i];
if (string.IsNullOrEmpty(layer))
continue;
var property = layout.AddPropertyItem($"{i}: {layer}");
var property = layout.AddPropertyItem(layer);
var checkbox = property.Checkbox().CheckBox;
UpdateCheckbox(checkbox, i);
checkbox.Tag = i;
checkbox.StateChanged += OnCheckboxStateChanged;
_checkBoxes.Add(checkbox);
_checkBoxes[i] = checkbox;
}
}
@@ -53,9 +50,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
if (_checkBoxes != null)
{
for (int i = 0; i < _checkBoxes.Count; i++)
for (int i = 0; i < _checkBoxes.Length; i++)
{
UpdateCheckbox(_checkBoxes[i], (int)_checkBoxes[i].Tag);
UpdateCheckbox(_checkBoxes[i], i);
}
}

View File

@@ -456,57 +456,14 @@ namespace FlaxEditor.CustomEditors.Dedicated
for (int i = 0; i < layout.Children.Count; i++)
{
if (layout.Children[i] is GroupElement group && group.Panel.HeaderText.Equals("Transform", StringComparison.Ordinal))
if (layout.Children[i] is GroupElement group && group.Panel.HeaderText == "Transform")
{
layout.Children.Remove(group);
layout.ContainerControl.Children.Remove(group.Panel);
VerticalPanelElement mainHor = VerticalPanelWithoutMargin(group);
CreateTransformElements(mainHor, ValuesTypes);
group.ContainerControl.ChangeChildIndex(mainHor.Control, 0);
break;
}
}
// Setup transform
if (Presenter is LayoutElementsContainer l)
{
for (int i = 0; i < l.Children.Count; i++)
{
if (l.Children[i] is GroupElement g && g.Panel.HeaderText.Equals("Transform", StringComparison.Ordinal))
{
l.Children.Remove(g);
l.ContainerControl.Children.Remove(g.Panel);
break;
}
}
var transformGroup = l.Group("Transform");
VerticalPanelElement mainHor = VerticalPanelWithoutMargin(transformGroup);
CreateTransformElements(mainHor, ValuesTypes);
ScriptMemberInfo scaleInfo = ValuesTypes[0].GetProperty("Scale");
ItemInfo scaleItem = new ItemInfo(scaleInfo);
transformGroup.Property("Scale", scaleItem.GetValues(Values));
ScriptMemberInfo pivotInfo = ValuesTypes[0].GetProperty("Pivot");
ItemInfo pivotItem = new ItemInfo(pivotInfo);
transformGroup.Property("Pivot", pivotItem.GetValues(Values));
ScriptMemberInfo shearInfo = ValuesTypes[0].GetProperty("Shear");
ItemInfo shearItem = new ItemInfo(shearInfo);
transformGroup.Property("Shear", shearItem.GetValues(Values));
ScriptMemberInfo rotationInfo = ValuesTypes[0].GetProperty("Rotation");
ItemInfo rotationItem = new ItemInfo(rotationInfo);
transformGroup.Property("Rotation", rotationItem.GetValues(Values));
// Get position of general tab
for (int i = 0; i < l.Children.Count; i++)
{
if (l.Children[i] is GroupElement g && g.Panel.HeaderText.Equals("General", StringComparison.Ordinal) && i + 1 <= l.Children.Count)
{
Presenter.ContainerControl.ChangeChildIndex(transformGroup.Control, i + 1);
break;
}
}
}
}
private void CreateTransformElements(LayoutElementsContainer main, ScriptType[] valueTypes)
@@ -688,7 +645,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
{
var grid = UniformGridTwoByOne(el);
grid.CustomControl.SlotPadding = new Margin(5, 5, 1, 1);
var label = grid.Label(text, TextAlignment.Far);
var label = grid.Label(text);
var editor = grid.Object(values);
if (editor is FloatEditor floatEditor && floatEditor.Element is FloatValueElement floatEditorElement)
{

View File

@@ -6,7 +6,6 @@ using FlaxEditor.Content;
using FlaxEditor.GUI;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
namespace FlaxEditor.CustomEditors.Editors
@@ -51,6 +50,7 @@ namespace FlaxEditor.CustomEditors.Editors
if (HasDifferentTypes)
return;
Picker = layout.Custom<AssetPicker>().CustomControl;
var value = Values[0];
_valueType = Values.Type.Type != typeof(object) || value == null ? Values.Type : TypeUtils.GetObjectType(value);
var assetType = _valueType;
@@ -58,8 +58,37 @@ namespace FlaxEditor.CustomEditors.Editors
assetType = new ScriptType(typeof(Asset));
else if (_valueType.Type != null && _valueType.Type.Name == typeof(JsonAssetReference<>).Name)
assetType = new ScriptType(_valueType.Type.GenericTypeArguments[0]);
float height = 48;
var attributes = Values.GetAttributes();
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
if (assetReference != null)
{
if (assetReference.UseSmallPicker)
height = 32;
if (string.IsNullOrEmpty(assetReference.TypeName))
{
}
else if (assetReference.TypeName.Length > 1 && assetReference.TypeName[0] == '.')
{
// Generic file picker
assetType = ScriptType.Null;
Picker.Validator.FileExtension = assetReference.TypeName;
}
else
{
var customType = TypeUtils.GetType(assetReference.TypeName);
if (customType != ScriptType.Null)
assetType = customType;
else if (!Content.Settings.GameSettings.OptionalPlatformSettings.Contains(assetReference.TypeName))
Debug.LogWarning(string.Format("Unknown asset type '{0}' to use for asset picker filter.", assetReference.TypeName));
else
assetType = ScriptType.Void;
}
}
Picker.Validator.AssetType = assetType;
ApplyAssetReferenceAttribute(Values, out var height, Picker.Validator);
Picker.Height = height;
Picker.SelectedItemChanged += OnSelectedItemChanged;
}
@@ -86,37 +115,6 @@ namespace FlaxEditor.CustomEditors.Editors
SetValue(Picker.Validator.SelectedAsset);
}
internal static void ApplyAssetReferenceAttribute(ValueContainer values, out float height, AssetPickerValidator validator)
{
height = 48;
var attributes = values.GetAttributes();
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
if (assetReference != null)
{
if (assetReference.UseSmallPicker)
height = 32;
if (string.IsNullOrEmpty(assetReference.TypeName))
{
}
else if (assetReference.TypeName.Length > 1 && assetReference.TypeName[0] == '.')
{
// Generic file picker
validator.AssetType = ScriptType.Null;
validator.FileExtension = assetReference.TypeName;
}
else
{
var customType = TypeUtils.GetType(assetReference.TypeName);
if (customType != ScriptType.Null)
validator.AssetType = customType;
else if (!Content.Settings.GameSettings.OptionalPlatformSettings.Contains(assetReference.TypeName))
Debug.LogWarning(string.Format("Unknown asset type '{0}' to use for asset picker filter.", assetReference.TypeName));
else
validator.AssetType = ScriptType.Void;
}
}
}
/// <inheritdoc />
public override void Refresh()
{
@@ -142,155 +140,4 @@ namespace FlaxEditor.CustomEditors.Editors
}
}
}
/// <summary>
/// Default implementation of the inspector used to edit reference to the files via path (absolute or relative to the project).
/// </summary>
/// <remarks>Supports editing reference to the asset via path using various containers: <see cref="Asset"/> or <see cref="AssetItem"/> or <see cref="System.String"/>.</remarks>
public class FilePathEditor : CustomEditor
{
private sealed class TextBoxWithPicker : TextBox
{
private const float DropdownIconMargin = 3.0f;
private const float DropdownIconSize = 12.0f;
private Rectangle DropdownRect => new Rectangle(Width - DropdownIconSize - DropdownIconMargin, DropdownIconMargin, DropdownIconSize, DropdownIconSize);
public Action ShowPicker;
public override void Draw()
{
base.Draw();
var style = FlaxEngine.GUI.Style.Current;
var dropdownRect = DropdownRect;
Render2D.DrawSprite(style.ArrowDown, dropdownRect, Enabled ? (DropdownRect.Contains(PointFromWindow(RootWindow.MousePosition)) ? style.BorderSelected : style.Foreground) : style.ForegroundDisabled);
}
public override bool OnMouseDown(Float2 location, MouseButton button)
{
if (DropdownRect.Contains(ref location))
{
Focus();
ShowPicker();
return true;
}
return base.OnMouseDown(location, button);
}
public override void OnMouseMove(Float2 location)
{
base.OnMouseMove(location);
if (DropdownRect.Contains(ref location))
Cursor = CursorType.Default;
else
Cursor = CursorType.IBeam;
}
protected override Rectangle TextRectangle
{
get
{
var result = base.TextRectangle;
result.Size.X -= DropdownIconSize + DropdownIconMargin * 2;
return result;
}
}
protected override Rectangle TextClipRectangle
{
get
{
var result = base.TextClipRectangle;
result.Size.X -= DropdownIconSize + DropdownIconMargin * 2;
return result;
}
}
}
private TextBoxWithPicker _textBox;
private AssetPickerValidator _validator;
private bool _isRefreshing;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
if (HasDifferentTypes)
return;
_textBox = layout.Custom<TextBoxWithPicker>().CustomControl;
_textBox.ShowPicker = OnShowPicker;
_textBox.EditEnd += OnEditEnd;
_validator = new AssetPickerValidator(ScriptType.Null);
AssetRefEditor.ApplyAssetReferenceAttribute(Values, out _, _validator);
}
private void OnShowPicker()
{
if (_validator.AssetType != ScriptType.Null)
AssetSearchPopup.Show(_textBox, _textBox.BottomLeft, _validator.IsValid, SetPickerPath);
else
ContentSearchPopup.Show(_textBox, _textBox.BottomLeft, _validator.IsValid, SetPickerPath);
}
private void SetPickerPath(ContentItem item)
{
var path = Utilities.Utils.ToPathProject(item.Path);
SetPath(path);
_isRefreshing = true;
_textBox.Defocus();
_textBox.Text = path;
_isRefreshing = false;
_textBox.RootWindow.Focus();
_textBox.Focus();
}
private void OnEditEnd()
{
SetPath(_textBox.Text);
}
private string GetPath()
{
var value = Values[0];
if (value is AssetItem assetItem)
return Utilities.Utils.ToPathProject(assetItem.Path);
if (value is Asset asset)
return Utilities.Utils.ToPathProject(asset.Path);
if (value is string str)
return str;
return null;
}
private void SetPath(string path)
{
if (_isRefreshing)
return;
var value = Values[0];
if (value is AssetItem)
SetValue(Editor.Instance.ContentDatabase.Find(Utilities.Utils.ToPathAbsolute(path)));
else if (value is Asset)
SetValue(FlaxEngine.Content.LoadAsync(path));
else if (value is string)
SetValue(path);
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
if (!HasDifferentValues)
{
_isRefreshing = true;
_textBox.Text = GetPath();
_isRefreshing = false;
}
}
}
}

View File

@@ -57,18 +57,17 @@ namespace FlaxEditor.CustomEditors.Editors
menu.ItemsContainer.RemoveChildren();
menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Paste", linkedEditor.Paste);
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste;
menu.AddSeparator();
b = menu.AddButton("Move up", OnMoveUpClicked);
b.Enabled = Index > 0 && !Editor._readOnly;
var moveUpButton = menu.AddButton("Move up", OnMoveUpClicked);
moveUpButton.Enabled = Index > 0;
b = menu.AddButton("Move down", OnMoveDownClicked);
b.Enabled = Index + 1 < Editor.Count && !Editor._readOnly;
b = menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly;
var moveDownButton = menu.AddButton("Move down", OnMoveDownClicked);
moveDownButton.Enabled = Index + 1 < Editor.Count;
menu.AddButton("Remove", OnRemoveClicked);
}
private void OnMoveUpClicked()
@@ -178,7 +177,6 @@ namespace FlaxEditor.CustomEditors.Editors
private IntValueBox _sizeBox;
private Color _background;
private int _elementsCount, _minCount, _maxCount;
private bool _readOnly;
private bool _canResize;
private bool _canReorderItems;
private CollectionAttribute.DisplayType _displayType;
@@ -211,7 +209,6 @@ namespace FlaxEditor.CustomEditors.Editors
return;
var size = Count;
_readOnly = false;
_canResize = true;
_canReorderItems = true;
_minCount = 0;
@@ -228,7 +225,6 @@ namespace FlaxEditor.CustomEditors.Editors
if (collection != null)
{
_canResize = !collection.ReadOnly;
_readOnly = collection.ReadOnly;
_minCount = collection.MinCount;
_maxCount = collection.MaxCount;
_canReorderItems = collection.CanReorderItems;
@@ -239,12 +235,6 @@ namespace FlaxEditor.CustomEditors.Editors
spacing = collection.Spacing;
_displayType = collection.Display;
}
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
{
_readOnly = true;
_canResize = false;
_canReorderItems = false;
}
if (_maxCount == 0)
_maxCount = ushort.MaxValue;
_canResize &= _minCount < _maxCount;
@@ -253,7 +243,8 @@ namespace FlaxEditor.CustomEditors.Editors
dragArea.CustomControl.Editor = this;
dragArea.CustomControl.ElementType = ElementType;
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter which scripts can be dragged over and dropped on this collection editor
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter
// which scripts can be dragged over and dropped on this collection editor.
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
if (assetReference != null)
{
@@ -342,8 +333,6 @@ namespace FlaxEditor.CustomEditors.Editors
var property = panel.AddPropertyItem(itemLabel);
var itemLayout = (LayoutElementsContainer)property;
itemLabel.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
}
else if (_displayType == CollectionAttribute.DisplayType.Header || (_displayType == CollectionAttribute.DisplayType.Default && !single))
{
@@ -351,15 +340,13 @@ namespace FlaxEditor.CustomEditors.Editors
cdp.CustomControl.Setup(this, i, _canReorderItems);
var itemLayout = cdp.VerticalPanel();
cdp.CustomControl.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
}
}
}
_elementsCount = size;
// Add/Remove buttons
if (_canResize && !_readOnly)
if (_canResize)
{
var panel = dragArea.HorizontalPanel();
panel.Panel.Size = new Float2(0, 20);

View File

@@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors
/// <inheritdoc />
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
{
if (button == MouseButton.Left && _editor._canEditKeys)
if (button == MouseButton.Left)
{
OnEditClicked(null);
return true;
@@ -197,11 +197,6 @@ namespace FlaxEditor.CustomEditors.Editors
spacing = collection.Spacing;
_displayType = collection.Display;
}
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
{
_readOnly = true;
_canEditKeys = false;
}
// Size
if (layout.ContainerControl is DropPanel dropPanel)
@@ -244,6 +239,14 @@ namespace FlaxEditor.CustomEditors.Editors
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
var valuesType = new ScriptType(valueType);
bool single = valuesType.IsPrimitive ||
valuesType.Equals(new ScriptType(typeof(string))) ||
valuesType.IsEnum ||
(valuesType.GetFields().Length == 1 && valuesType.GetProperties().Length == 0) ||
(valuesType.GetProperties().Length == 1 && valuesType.GetFields().Length == 0) ||
valuesType.Equals(new ScriptType(typeof(JsonAsset))) ||
valuesType.Equals(new ScriptType(typeof(SettingsBase)));
// Use separate layout cells for each collection items to improve layout updates for them in separation
var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum;
@@ -260,8 +263,6 @@ namespace FlaxEditor.CustomEditors.Editors
var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key));
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor);
if (_readOnly && itemLayout.Children.Count > 0)
GenericEditor.OnReadOnlyProperty(itemLayout);
}
}
_elementsCount = size;

View File

@@ -1,17 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
namespace FlaxEditor.CustomEditors.Editors
{
internal sealed class DummyEditor : CustomEditor
{
public override void Initialize(LayoutElementsContainer layout)
{
string valueName;
if (Values.Count != 0 && Values[0] != null)
valueName = Values[0].ToString();
else
valueName = "null";
layout.Label($"{valueName} ({Values.Type})");
}
}
}

View File

@@ -474,32 +474,7 @@ namespace FlaxEditor.CustomEditors.Editors
}
if (layout.Editors.Count != 0)
{
var sb = Clipboard.Text;
if (!string.IsNullOrEmpty(sb))
{
try
{
var data = JsonSerializer.Deserialize<string[]>(sb);
if (data == null || data.Length != layout.Editors.Count)
return false;
for (var i = 0; i < layout.Editors.Count; i++)
{
Clipboard.Text = data[i];
if (!layout.Editors[i].CanPaste)
return false;
}
return true;
}
catch
{
return false;
}
finally
{
Clipboard.Text = sb;
}
}
return false;
return !string.IsNullOrEmpty(Clipboard.Text);
}
if (layout.Children.Any(x => x is LayoutElementsContainer))
{
@@ -581,43 +556,6 @@ namespace FlaxEditor.CustomEditors.Editors
return layout;
}
internal static void OnReadOnlyProperty(LayoutElementsContainer itemLayout, int labelIndex = -1)
{
PropertiesListElement list = null;
int firstChildControlIndex = 0;
bool disableSingle = true;
var control = itemLayout.Children[itemLayout.Children.Count - 1];
if (control is GroupElement group && group.Children.Count > 0)
{
list = group.Children[0] as PropertiesListElement;
disableSingle = false; // Disable all nested editors
}
else if (control is PropertiesListElement list1 && labelIndex != -1)
{
list = list1;
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
}
else if (control?.Control != null)
{
control.Control.Enabled = false;
}
if (list != null)
{
// Disable controls added to the editor
var count = list.Properties.Children.Count;
for (int j = firstChildControlIndex; j < count; j++)
{
var child = list.Properties.Children[j];
if (disableSingle && child is PropertyNameLabel)
break;
if (child != null)
child.Enabled = false;
}
}
}
/// <summary>
/// Evaluate the <see cref="VisibleIfAttribute"/> cache for a given property item.
/// </summary>
@@ -697,7 +635,35 @@ namespace FlaxEditor.CustomEditors.Editors
if (item.IsReadOnly && itemLayout.Children.Count > 0)
{
OnReadOnlyProperty(itemLayout, labelIndex);
PropertiesListElement list = null;
int firstChildControlIndex = 0;
bool disableSingle = true;
var control = itemLayout.Children[itemLayout.Children.Count - 1];
if (control is GroupElement group && group.Children.Count > 0)
{
list = group.Children[0] as PropertiesListElement;
disableSingle = false; // Disable all nested editors
}
else if (control is PropertiesListElement list1)
{
list = list1;
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
}
if (list != null)
{
// Disable controls added to the editor
var count = list.Properties.Children.Count;
for (int j = firstChildControlIndex; j < count; j++)
{
var child = list.Properties.Children[j];
if (disableSingle && child is PropertyNameLabel)
break;
if (child != null)
child.Enabled = false;
}
}
}
EvaluateVisibleIf(itemLayout, item, labelIndex);

View File

@@ -25,7 +25,6 @@ namespace FlaxEditor.CustomEditors.Editors
new OptionType("Linear Gradient", typeof(LinearGradientBrush)),
new OptionType("Texture 9-Slicing", typeof(Texture9SlicingBrush)),
new OptionType("Sprite 9-Slicing", typeof(Sprite9SlicingBrush)),
new OptionType("Video", typeof(VideoBrush)),
};
}
}

View File

@@ -242,7 +242,7 @@ namespace FlaxEditor.CustomEditors.GUI
float namesWidth = _splitterValue * Width;
int count = _element.Labels.Count;
float[] yStarts = new float[count + 1];
for (int i = 0; i < count; i++)
for (int i = 1; i < count; i++)
{
var label = _element.Labels[i];
@@ -251,13 +251,9 @@ namespace FlaxEditor.CustomEditors.GUI
else if (_children.Count <= label.FirstChildControlIndex)
yStarts[i] = y;
else
{
yStarts[i] = _children[label.FirstChildControlIndex].Top;
if (i == count - 1)
yStarts[i + 1] = _children[label.FirstChildControlIndex].Bottom;
}
}
yStarts[count] = y;
for (int i = 0; i < count; i++)
{
var label = _element.Labels[i];

View File

@@ -5,8 +5,10 @@ using System.IO;
using FlaxEditor.Content;
using FlaxEditor.GUI.Drag;
using FlaxEditor.Scripting;
using FlaxEditor.Utilities;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
namespace FlaxEditor.GUI
{

View File

@@ -264,7 +264,6 @@ namespace FlaxEditor.GUI.Dialogs
{
Text = "+",
Parent = this,
TooltipText = "Save Color.",
Tag = null,
};
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
@@ -371,25 +370,9 @@ namespace FlaxEditor.GUI.Dialogs
Render2D.DrawText(style.FontMedium, "Hex", hex, textColor, TextAlignment.Near, TextAlignment.Center);
// Color difference
var newRect = new Rectangle(_cOK.X - 3, _cHex.Bottom + PickerMargin, 130, 0);
newRect.Size.Y = 50;
Render2D.FillRectangle(newRect, Color.White);
var smallRectSize = 10;
var numHor = Mathf.FloorToInt(newRect.Width / smallRectSize);
var numVer = Mathf.FloorToInt(newRect.Height / smallRectSize);
// Draw checkerboard for background of color to help with transparency
for (int i = 0; i < numHor; i++)
{
for (int j = 0; j < numVer; j++)
{
if ((i + j) % 2 == 0 )
{
var rect = new Rectangle(newRect.X + smallRectSize * i, newRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.FillRectangle(rect, Color.Gray);
}
}
}
Render2D.FillRectangle(newRect, _value);
var newRect = new Rectangle(_cOK.X, _cHex.Bottom + PickerMargin, _cCancel.Right - _cOK.Left, 0);
newRect.Size.Y = _cValue.Bottom - newRect.Y;
Render2D.FillRectangle(newRect, _value * _value.A);
}
/// <inheritdoc />
@@ -515,7 +498,6 @@ namespace FlaxEditor.GUI.Dialogs
{
Text = "+",
Parent = this,
TooltipText = "Save Color.",
Tag = null,
};
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);

View File

@@ -311,9 +311,7 @@ namespace FlaxEditor.GUI.Dialogs
// Alpha
float alphaY = _slider2Rect.Height * (1 - _color.A);
var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);
var color = _color;
color.A = 1; // Keep slider 2 fill rect from changing color alpha while selecting.
Render2D.FillRectangle(_slider2Rect, color, color, Color.Transparent, Color.Transparent);
Render2D.FillRectangle(_slider2Rect, _color, _color, Color.Transparent, Color.Transparent);
Render2D.DrawRectangle(_slider2Rect, _isMouseDownSlider2 ? style.BackgroundSelected : Color.Black);
Render2D.DrawRectangle(alphaR, _isMouseDownSlider2 ? Color.White : Color.Gray);
}

View File

@@ -418,19 +418,9 @@ namespace FlaxEditor.GUI.Tabs
{
// If scroll bar is visible it covers part of the tab header so include this in tab size to improve usability
if (_orientation == Orientation.Horizontal && TabsPanel.HScrollBar.Visible)
{
tabsSize.Y += TabsPanel.HScrollBar.Height;
var style = Style.Current;
TabsPanel.HScrollBar.TrackColor = style.Background;
TabsPanel.HScrollBar.ThumbColor = style.ForegroundGrey;
}
else if (_orientation == Orientation.Vertical && TabsPanel.VScrollBar.Visible)
{
tabsSize.X += TabsPanel.VScrollBar.Width;
var style = Style.Current;
TabsPanel.VScrollBar.TrackColor = style.Background;
TabsPanel.VScrollBar.ThumbColor = style.ForegroundGrey;
}
}
// Fit the tabs panel

View File

@@ -698,38 +698,6 @@ namespace FlaxEditor.GUI.Tree
}
}
// Show tree guide lines
if (Editor.Instance.Options.Options.Interface.ShowTreeLines)
{
TreeNode parentNode = Parent as TreeNode;
bool thisNodeIsLast = false;
while (parentNode != null && parentNode != ParentTree.Children[0])
{
float bottomOffset = 0;
float topOffset = 0;
if (Parent == parentNode && this == Parent.Children[0])
topOffset = 2;
if (thisNodeIsLast && parentNode.Children.Count == 1)
bottomOffset = topOffset != 0 ? 4 : 2;
if (Parent == parentNode && this == Parent.Children[Parent.Children.Count - 1] && !_opened)
{
thisNodeIsLast = true;
bottomOffset = topOffset != 0 ? 4 : 2;
}
float leftOffset = 9;
// Adjust offset for icon image
if (_iconCollaped.IsValid)
leftOffset += 18;
var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset);
Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground);
parentNode = parentNode.Parent as TreeNode;
}
}
// Base
if (_opened)
{
@@ -761,7 +729,7 @@ namespace FlaxEditor.GUI.Tree
// Try to estimate the rough location of the first node, assuming the node height is constant
var firstChildGlobalRect = GetChildGlobalRectangle(children[0], ref globalTransform);
var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Y - firstChildGlobalRect.Top) / _headerHeight) + 1, 0, children.Count - 1);
var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Y - firstChildGlobalRect.Top) / firstChildGlobalRect.Height) + 1, 0, children.Count - 1);
if (GetChildGlobalRectangle(children[firstVisibleChild], ref globalTransform).Top > globalClipping.Top || !children[firstVisibleChild].Visible)
{
// Estimate overshoot, either it's partially visible or hidden in the tree

View File

@@ -499,15 +499,6 @@ namespace FlaxEditor
bool drawAnySelectedControl = false;
var transformGizmo = TransformGizmo;
var mousePos = PointFromWindow(RootWindow.MousePosition);
if (EnableSelecting && !_mouseMovesControl && !_mouseMovesWidget && IsMouseOver)
{
// Highlight control under mouse for easier selecting (except if already selected)
if (RayCastControl(ref mousePos, out var hitControl) &&
(transformGizmo == null || !transformGizmo.Selection.Any(x => x.EditableObject is UIControl controlActor && controlActor.Control == hitControl)))
{
DrawControl(null, hitControl, false, ref mousePos, ref drawAnySelectedControl);
}
}
if (transformGizmo != null)
{
// Selected UI controls outline
@@ -520,6 +511,15 @@ namespace FlaxEditor
}
}
}
if (EnableSelecting && !_mouseMovesControl && !_mouseMovesWidget && IsMouseOver)
{
// Highlight control under mouse for easier selecting (except if already selected)
if (RayCastControl(ref mousePos, out var hitControl) &&
(transformGizmo == null || !transformGizmo.Selection.Any(x => x.EditableObject is UIControl controlActor && controlActor.Control == hitControl)))
{
DrawControl(null, hitControl, false, ref mousePos, ref drawAnySelectedControl);
}
}
if (drawAnySelectedControl)
Render2D.PopTransform();
@@ -617,39 +617,40 @@ namespace FlaxEditor
// Draw sizing widgets
if (_widgets == null)
_widgets = new List<Widget>();
var widgetSize = 10.0f;
var widgetSize = 8.0f;
var viewScale = ViewScale;
if (viewScale < 0.7f)
widgetSize *= viewScale;
var controlSize = control.Size.Absolute.MinValue / 50.0f;
if (controlSize < 1.0f)
widgetSize *= Mathf.Clamp(controlSize + 0.1f, 0.1f, 1.0f);
var widgetHandleSize = new Float2(widgetSize);
DrawControlWidget(uiControl, ref ul, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, -1), CursorType.SizeNWSE);
DrawControlWidget(uiControl, ref ur, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, -1), CursorType.SizeNESW);
DrawControlWidget(uiControl, ref bl, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, 1), CursorType.SizeNESW);
DrawControlWidget(uiControl, ref br, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, 1), CursorType.SizeNWSE);
var cornerSize = new Float2(widgetSize);
DrawControlWidget(uiControl, ref ul, ref mousePos, ref cornerSize, new Float2(-1, -1), CursorType.SizeNWSE);
DrawControlWidget(uiControl, ref ur, ref mousePos, ref cornerSize, new Float2(1, -1), CursorType.SizeNESW);
DrawControlWidget(uiControl, ref bl, ref mousePos, ref cornerSize, new Float2(-1, 1), CursorType.SizeNESW);
DrawControlWidget(uiControl, ref br, ref mousePos, ref cornerSize, new Float2(1, 1), CursorType.SizeNWSE);
var edgeSizeV = new Float2(widgetSize * 2, widgetSize);
var edgeSizeH = new Float2(edgeSizeV.Y, edgeSizeV.X);
Float2.Lerp(ref ul, ref bl, 0.5f, out var el);
Float2.Lerp(ref ur, ref br, 0.5f, out var er);
Float2.Lerp(ref ul, ref ur, 0.5f, out var eu);
Float2.Lerp(ref bl, ref br, 0.5f, out var eb);
DrawControlWidget(uiControl, ref el, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, 0), CursorType.SizeWE);
DrawControlWidget(uiControl, ref er, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, 0), CursorType.SizeWE);
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
DrawControlWidget(uiControl, ref el, ref mousePos, ref edgeSizeH, new Float2(-1, 0), CursorType.SizeWE);
DrawControlWidget(uiControl, ref er, ref mousePos, ref edgeSizeH, new Float2(1, 0), CursorType.SizeWE);
DrawControlWidget(uiControl, ref eu, ref mousePos, ref edgeSizeV, new Float2(0, -1), CursorType.SizeNS);
DrawControlWidget(uiControl, ref eb, ref mousePos, ref edgeSizeV, new Float2(0, 1), CursorType.SizeNS);
// TODO: draw anchors
}
}
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size,float scale, Float2 resizeAxis, CursorType cursor)
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, Float2 resizeAxis, CursorType cursor)
{
var style = Style.Current;
var rect = new Rectangle((pos + resizeAxis * 10 * scale) - size * 0.5f, size);
var rect = new Rectangle(pos - size * 0.5f, size);
if (rect.Contains(ref mousePos))
{
Render2D.FillRectangle(rect, style.Foreground);
Render2D.DrawRectangle(rect, style.SelectionBorder);
}
else
{

View File

@@ -129,9 +129,12 @@ namespace FlaxEditor.Modules
for (int i = 0; i < Proxy.Count; i++)
{
if (Proxy[i].IsProxyFor(item))
{
return Proxy[i];
}
}
}
return null;
}
@@ -144,8 +147,11 @@ namespace FlaxEditor.Modules
for (int i = 0; i < Proxy.Count; i++)
{
if (Proxy[i].IsProxyFor<T>())
{
return Proxy[i];
}
}
return null;
}
@@ -158,12 +164,17 @@ namespace FlaxEditor.Modules
{
if (string.IsNullOrEmpty(extension))
throw new ArgumentNullException();
extension = StringUtils.NormalizeExtension(extension);
for (int i = 0; i < Proxy.Count; i++)
{
if (string.Equals(Proxy[i].FileExtension, extension, StringComparison.Ordinal))
if (Proxy[i].FileExtension == extension)
{
return Proxy[i];
}
}
return null;
}
@@ -178,23 +189,30 @@ namespace FlaxEditor.Modules
for (int i = 0; i < Proxy.Count; i++)
{
if (Proxy[i] is AssetProxy proxy && proxy.AcceptsAsset(typeName, path))
{
return proxy;
}
}
return null;
}
/// <summary>
/// Gets the virtual proxy object from given path.
/// <br></br>use case if the asset u trying to display is not a flax asset but u like to add custom functionality
/// <br></br>to context menu,or display it the asset
/// </summary>
/// <param name="path">The asset path.</param>
/// <returns>Asset proxy or null if cannot find.</returns>
public AssetProxy GetAssetVirtualProxy(string path)
public AssetProxy GetAssetVirtuallProxy(string path)
{
for (int i = 0; i < Proxy.Count; i++)
{
if (Proxy[i] is AssetProxy proxy && proxy.IsVirtualProxy() && path.EndsWith(proxy.FileExtension, StringComparison.OrdinalIgnoreCase))
{
return proxy;
}
}
return null;
}
@@ -998,13 +1016,11 @@ namespace FlaxEditor.Modules
}
if (item == null)
{
var proxy = GetAssetVirtualProxy(path);
var proxy = GetAssetVirtuallProxy(path);
item = proxy?.ConstructItem(path, assetInfo.TypeName, ref assetInfo.ID);
if (item == null)
{
item = GetProxy(Path.GetExtension(path))?.ConstructItem(path);
if (item == null)
item = new FileItem(path);
item = new FileItem(path);
}
}
@@ -1090,7 +1106,6 @@ namespace FlaxEditor.Modules
Proxy.Add(new VisualScriptProxy());
Proxy.Add(new BehaviorTreeProxy());
Proxy.Add(new LocalizedStringTableProxy());
Proxy.Add(new VideoProxy("mp4"));
Proxy.Add(new WidgetProxy());
Proxy.Add(new FileProxy());
Proxy.Add(new SpawnableJsonAssetProxy<PhysicalMaterial>());

View File

@@ -175,13 +175,6 @@ namespace FlaxEditor.Options
[EditorDisplay("Interface", "New Window Location"), EditorOrder(150), Tooltip("Define the opening method for new windows, open in a new tab by default.")]
public DockStateProxy NewWindowLocation { get; set; } = DockStateProxy.Float;
/// <summary>
/// Gets or sets the timestamps prefix mode for debug log messages.
/// </summary>
[DefaultValue(TimestampsFormats.None)]
[EditorDisplay("Interface"), EditorOrder(210), Tooltip("The timestamps prefix mode for debug log messages.")]
public TimestampsFormats DebugLogTimestampsFormat { get; set; } = TimestampsFormats.None;
/// <summary>
/// Gets or sets the editor icons scale. Editor restart required.
/// </summary>
@@ -211,30 +204,72 @@ namespace FlaxEditor.Options
public bool SeparateValueAndUnit { get; set; }
/// <summary>
/// Gets or sets the option to put a space between numbers and units for unit formatting.
/// Gets or sets the timestamps prefix mode for debug log messages.
/// </summary>
[DefaultValue(TimestampsFormats.None)]
[EditorDisplay("Debug Log"), EditorOrder(300), Tooltip("The timestamps prefix mode for debug log messages.")]
public TimestampsFormats DebugLogTimestampsFormat { get; set; } = TimestampsFormats.None;
/// <summary>
/// Gets or sets the clear on play for debug log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Interface"), EditorOrder(320)]
public bool ShowTreeLines { get; set; } = true;
[EditorDisplay("Debug Log", "Clear on Play"), EditorOrder(310), Tooltip("Clears all log entries on enter playmode.")]
public bool DebugLogClearOnPlay { get; set; } = true;
/// <summary>
/// Gets or sets the collapse mode for debug log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Debug Log"), EditorOrder(312), Tooltip("Collapses similar or repeating log entries.")]
public bool DebugLogCollapse { get; set; } = true;
/// <summary>
/// Gets or sets the automatic pause on error for debug log messages.
/// </summary>
[DefaultValue(false)]
[EditorDisplay("Debug Log", "Pause on Error"), EditorOrder(314), Tooltip("Performs auto pause on error.")]
public bool DebugLogPauseOnError { get; set; } = false;
/// <summary>
/// Gets or sets the automatic pause on error for debug log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Debug Log", "Show error messages"), EditorOrder(320), Tooltip("Shows/hides error messages.")]
public bool DebugLogShowErrorMessages { get; set; } = true;
/// <summary>
/// Gets or sets the automatic pause on error for debug log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Debug Log", "Show warning messages"), EditorOrder(322), Tooltip("Shows/hides warning messages.")]
public bool DebugLogShowWarningMessages { get; set; } = true;
/// <summary>
/// Gets or sets the automatic pause on error for debug log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Debug Log", "Show info messages"), EditorOrder(324), Tooltip("Shows/hides info messages.")]
public bool DebugLogShowInfoMessages { get; set; } = true;
/// <summary>
/// Gets or sets the timestamps prefix mode for output log messages.
/// </summary>
[DefaultValue(TimestampsFormats.TimeSinceStartup)]
[EditorDisplay("Output Log", "Timestamps Format"), EditorOrder(300), Tooltip("The timestamps prefix mode for output log messages.")]
[EditorDisplay("Output Log", "Timestamps Format"), EditorOrder(400), Tooltip("The timestamps prefix mode for output log messages.")]
public TimestampsFormats OutputLogTimestampsFormat { get; set; } = TimestampsFormats.TimeSinceStartup;
/// <summary>
/// Gets or sets the timestamps prefix mode for output log messages.
/// Gets or sets the log type prefix mode for output log messages.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Output Log", "Show Log Type"), EditorOrder(310), Tooltip("Determines whether show log type prefix in output log messages.")]
[EditorDisplay("Output Log", "Show Log Type"), EditorOrder(410), Tooltip("Determines whether show log type prefix in output log messages.")]
public bool OutputLogShowLogType { get; set; } = true;
/// <summary>
/// Gets or sets the output log text font.
/// </summary>
[EditorDisplay("Output Log", "Text Font"), EditorOrder(320), Tooltip("The output log text font.")]
[EditorDisplay("Output Log", "Text Font"), EditorOrder(420), Tooltip("The output log text font.")]
public FontReference OutputLogTextFont
{
get => _outputLogFont;
@@ -253,63 +288,70 @@ namespace FlaxEditor.Options
/// Gets or sets the output log text color.
/// </summary>
[DefaultValue(typeof(Color), "1,1,1,1")]
[EditorDisplay("Output Log", "Text Color"), EditorOrder(330), Tooltip("The output log text color.")]
[EditorDisplay("Output Log", "Text Color"), EditorOrder(430), Tooltip("The output log text color.")]
public Color OutputLogTextColor { get; set; } = Color.White;
/// <summary>
/// Gets or sets the output log text shadow color.
/// </summary>
[DefaultValue(typeof(Color), "0,0,0,0.5")]
[EditorDisplay("Output Log", "Text Shadow Color"), EditorOrder(340), Tooltip("The output log text shadow color.")]
[EditorDisplay("Output Log", "Text Shadow Color"), EditorOrder(440), Tooltip("The output log text shadow color.")]
public Color OutputLogTextShadowColor { get; set; } = new Color(0, 0, 0, 0.5f);
/// <summary>
/// Gets or sets the output log text shadow offset. Set to 0 to disable this feature.
/// </summary>
[DefaultValue(typeof(Float2), "1,1")]
[EditorDisplay("Output Log", "Text Shadow Offset"), EditorOrder(340), Tooltip("The output log text shadow offset. Set to 0 to disable this feature.")]
[EditorDisplay("Output Log", "Text Shadow Offset"), EditorOrder(445), Tooltip("The output log text shadow offset. Set to 0 to disable this feature.")]
public Float2 OutputLogTextShadowOffset { get; set; } = new Float2(1);
/// <summary>
/// Gets or sets a value indicating whether auto-focus output log window on code compilation error.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Output Log", "Focus Output Log On Compilation Error"), EditorOrder(350), Tooltip("Determines whether auto-focus output log window on code compilation error.")]
[EditorDisplay("Output Log", "Focus Output Log On Compilation Error"), EditorOrder(450), Tooltip("Determines whether auto-focus output log window on code compilation error.")]
public bool FocusOutputLogOnCompilationError { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether auto-focus output log window on game build error.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Output Log", "Focus Output Log On Game Build Error"), EditorOrder(360), Tooltip("Determines whether auto-focus output log window on game build error.")]
[EditorDisplay("Output Log", "Focus Output Log On Game Build Error"), EditorOrder(460), Tooltip("Determines whether auto-focus output log window on game build error.")]
public bool FocusOutputLogOnGameBuildError { get; set; } = true;
/// <summary>
/// Gets or sets the value for automatic scroll to bottom in output log.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Output Log", "Scroll to bottom"), EditorOrder(470), Tooltip("Scroll the output log view to bottom automatically after new lines are added.")]
public bool OutputLogScrollToBottom { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating whether auto-focus game window on play mode start.
/// </summary>
[DefaultValue(true)]
[EditorDisplay("Play In-Editor", "Focus Game Window On Play"), EditorOrder(400), Tooltip("Determines whether auto-focus game window on play mode start.")]
[EditorDisplay("Play In-Editor", "Focus Game Window On Play"), EditorOrder(500), Tooltip("Determines whether auto-focus game window on play mode start.")]
public bool FocusGameWinOnPlay { get; set; } = true;
/// <summary>
/// Gets or sets a value indicating what action should be taken upon pressing the play button.
/// </summary>
[DefaultValue(PlayAction.PlayScenes)]
[EditorDisplay("Play In-Editor", "Play Button Action"), EditorOrder(410)]
[EditorDisplay("Play In-Editor", "Play Button Action"), EditorOrder(510)]
public PlayAction PlayButtonAction { get; set; } = PlayAction.PlayScenes;
/// <summary>
/// Gets or sets a value indicating how the game window should be displayed when the game is launched.
/// </summary>
[DefaultValue(GameWindowMode.Docked)]
[EditorDisplay("Play In-Editor", "Game Window Mode"), EditorOrder(420), Tooltip("Determines how the game window is displayed when the game is launched.")]
[EditorDisplay("Play In-Editor", "Game Window Mode"), EditorOrder(520), Tooltip("Determines how the game window is displayed when the game is launched.")]
public GameWindowMode DefaultGameWindowMode { get; set; } = GameWindowMode.Docked;
/// <summary>
/// Gets or sets a value indicating the number of game clients to launch when building and/or running cooked game.
/// </summary>
[DefaultValue(1), Range(1, 4)]
[EditorDisplay("Cook & Run"), EditorOrder(500)]
[EditorDisplay("Cook & Run"), EditorOrder(600)]
public int NumberOfGameClientsToLaunch = 1;
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont);
@@ -324,13 +366,13 @@ namespace FlaxEditor.Options
/// <summary>
/// The list of fallback fonts to use when main text font is missing certain characters. Empty to use fonts from GraphicsSettings.
/// </summary>
[EditorDisplay("Fonts"), EditorOrder(650)]
[EditorDisplay("Fonts"), EditorOrder(750)]
public FontAsset[] FallbackFonts = new FontAsset[1] { FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.FallbackFont) };
/// <summary>
/// Gets or sets the title font for editor UI.
/// </summary>
[EditorDisplay("Fonts"), EditorOrder(600), Tooltip("The title font for editor UI.")]
[EditorDisplay("Fonts"), EditorOrder(700), Tooltip("The title font for editor UI.")]
public FontReference TitleFont
{
get => _titleFont;
@@ -348,7 +390,7 @@ namespace FlaxEditor.Options
/// <summary>
/// Gets or sets the large font for editor UI.
/// </summary>
[EditorDisplay("Fonts"), EditorOrder(610), Tooltip("The large font for editor UI.")]
[EditorDisplay("Fonts"), EditorOrder(710), Tooltip("The large font for editor UI.")]
public FontReference LargeFont
{
get => _largeFont;
@@ -366,7 +408,7 @@ namespace FlaxEditor.Options
/// <summary>
/// Gets or sets the medium font for editor UI.
/// </summary>
[EditorDisplay("Fonts"), EditorOrder(620), Tooltip("The medium font for editor UI.")]
[EditorDisplay("Fonts"), EditorOrder(720), Tooltip("The medium font for editor UI.")]
public FontReference MediumFont
{
get => _mediumFont;
@@ -384,7 +426,7 @@ namespace FlaxEditor.Options
/// <summary>
/// Gets or sets the small font for editor UI.
/// </summary>
[EditorDisplay("Fonts"), EditorOrder(630), Tooltip("The small font for editor UI.")]
[EditorDisplay("Fonts"), EditorOrder(730), Tooltip("The small font for editor UI.")]
public FontReference SmallFont
{
get => _smallFont;

View File

@@ -255,17 +255,6 @@ namespace FlaxEditor.Options
}
}
// Ensure custom fonts are valid, reset if not
var defaultInterfaceOptions = new InterfaceOptions();
if (Style.Current.FontTitle == null)
Style.Current.FontTitle = defaultInterfaceOptions.TitleFont.GetFont();
if (Style.Current.FontSmall == null)
Style.Current.FontSmall = defaultInterfaceOptions.SmallFont.GetFont();
if (Style.Current.FontMedium == null)
Style.Current.FontMedium = defaultInterfaceOptions.MediumFont.GetFont();
if (Style.Current.FontLarge == null)
Style.Current.FontLarge = defaultInterfaceOptions.LargeFont.GetFont();
// Set fallback fonts
var fallbackFonts = Options.Interface.FallbackFonts;
if (fallbackFonts == null || fallbackFonts.Length == 0 || fallbackFonts.All(x => x == null))

View File

@@ -1,69 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using System;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Custom editor for <see cref="VideoPlayer"/>.
/// </summary>
[CustomEditor(typeof(VideoPlayer)), DefaultEditor]
public class VideoPlayerEditor : ActorEditor
{
private Label _infoLabel;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
base.Initialize(layout);
// Show playback options during simulation
if (Editor.IsPlayMode)
{
var playbackGroup = layout.Group("Playback");
playbackGroup.Panel.Open();
_infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true;
var grid = playbackGroup.CustomContainer<UniformGridPanel>();
var gridControl = grid.CustomControl;
gridControl.ClipChildren = false;
gridControl.Height = Button.DefaultHeight;
gridControl.SlotsHorizontally = 3;
gridControl.SlotsVertically = 1;
grid.Button("Play").Button.Clicked += () => Foreach(x => x.Play());
grid.Button("Pause").Button.Clicked += () => Foreach(x => x.Pause());
grid.Button("Stop").Button.Clicked += () => Foreach(x => x.Stop());
}
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
if (_infoLabel != null)
{
var text = string.Empty;
foreach (var value in Values)
{
if (value is VideoPlayer player)
text += $"Time: {player.Time:##0.0}s / {player.Duration:##0.0}s\nResolution: {player.Size.X}x{player.Size.Y}, Frame Rate: {player.FrameRate}";
}
_infoLabel.Text = text;
}
}
private void Foreach(Action<VideoPlayer> func)
{
foreach (var value in Values)
{
if (value is VideoPlayer player)
func(player);
}
}
}
}

View File

@@ -15,7 +15,6 @@ using FlaxEditor.Windows.Assets;
using FlaxEngine;
using FlaxEngine.GUI;
using FlaxEngine.Utilities;
using Object = FlaxEngine.Object;
namespace FlaxEditor.SceneGraph.GUI
{
@@ -356,7 +355,7 @@ namespace FlaxEditor.SceneGraph.GUI
private void OnRenamed(RenamePopup renamePopup)
{
using (new UndoBlock(ActorNode.Root.Undo, Actor, "Rename"))
Actor.Name = renamePopup.Text.Trim();
Actor.Name = renamePopup.Text;
}
/// <inheritdoc />
@@ -626,7 +625,6 @@ namespace FlaxEditor.SceneGraph.GUI
{
var item = _dragScriptItems.Objects[i];
var actorType = Editor.Instance.CodeEditing.Actors.Get(item);
var scriptType = Editor.Instance.CodeEditing.Scripts.Get(item);
if (actorType != ScriptType.Null)
{
var actor = actorType.CreateInstance() as Actor;
@@ -641,18 +639,6 @@ namespace FlaxEditor.SceneGraph.GUI
ActorNode.Root.Spawn(actor, spawnParent);
actor.OrderInParent = newOrder;
}
else if (scriptType != ScriptType.Null)
{
if (DragOverMode == DragItemPositioning.Above || DragOverMode == DragItemPositioning.Below)
{
Editor.LogWarning("Failed to spawn script of type " + actorType.TypeName);
continue;
}
IUndoAction action = new AddRemoveScript(true, newParent, scriptType);
Select();
ActorNode.Root.Undo?.AddAction(action);
action.Do();
}
}
result = DragDropEffect.Move;
}
@@ -713,9 +699,9 @@ namespace FlaxEditor.SceneGraph.GUI
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
}
private bool ValidateDragScriptItem(ScriptItem script)
private static bool ValidateDragScriptItem(ScriptItem script)
{
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null || Editor.Instance.CodeEditing.Scripts.Get(script) != ScriptType.Null;
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
}
/// <inheritdoc />

View File

@@ -430,7 +430,7 @@ namespace FlaxEditor.Surface.Archetypes
Title = "Smoothstep",
Description = "Returns a smooth Hermite interpolation between 0 and 1, if value is in the range [min, max].",
Flags = NodeFlags.MaterialGraph,
Size = new Float2(200, 60),
Size = new Float2(120, 60),
ConnectionsHints = ConnectionsHint.Numeric,
IndependentBoxes = new[] { 0, 1, 2 },
DependentBoxes = new[] { 3 },

View File

@@ -190,15 +190,7 @@ namespace FlaxEditor.Surface
if (data == null || data.Length < 2)
return false;
try
{
var model = JsonConvert.DeserializeObject<DataModel>(data);
return model?.Nodes != null && model.Nodes.Length != 0;
}
catch (Exception)
{
return false;
}
return true;
}
/// <summary>
@@ -215,7 +207,15 @@ namespace FlaxEditor.Surface
try
{
// Load Mr Json
var model = FlaxEngine.Json.JsonSerializer.Deserialize<DataModel>(data);
DataModel model;
try
{
model = FlaxEngine.Json.JsonSerializer.Deserialize<DataModel>(data);
}
catch
{
return;
}
if (model.Nodes == null)
model.Nodes = new DataModelNode[0];

View File

@@ -7,7 +7,7 @@
enum class PixelFormat : unsigned;
enum class DirectorySearchOption;
class TextureData;
struct TextureData;
/// <summary>
/// Helper functions for the editor.

View File

@@ -1471,27 +1471,5 @@ namespace FlaxEditor.Utilities
inputActions.Add(options => options.GenerateScriptsProject, () => Editor.Instance.ProgressReporting.GenerateScriptsProjectFiles.RunAsync());
inputActions.Add(options => options.RecompileScripts, ScriptsBuilder.Compile);
}
internal static string ToPathProject(string path)
{
if (path != null)
{
// Convert into path relative to the project (cross-platform)
var projectFolder = Globals.ProjectFolder;
if (path.StartsWith(projectFolder))
path = path.Substring(projectFolder.Length + 1);
}
return path;
}
internal static string ToPathAbsolute(string path)
{
if (path != null)
{
// Convert into global path to if relative to the project
path = StringUtils.IsRelative(path) ? Path.Combine(Globals.ProjectFolder, path) : path;
}
return path;
}
}
}

View File

@@ -21,7 +21,6 @@
#include "Engine/Level/Actors/Sky.h"
#include "Engine/Level/Actors/SkyLight.h"
#include "Engine/Level/Actors/SpotLight.h"
#include "Engine/Video/VideoPlayer.h"
#define ICON_RADIUS 7.0f
@@ -284,7 +283,6 @@ bool ViewportIconsRendererService::Init()
MAP_TYPE(Sky, Skybox);
MAP_TYPE(SkyLight, SkyLight);
MAP_TYPE(SpotLight, PointLight);
MAP_TYPE(VideoPlayer, SceneAnimationPlayer);
#undef MAP_TYPE
return false;

View File

@@ -351,8 +351,6 @@ namespace FlaxEditor.Viewport
private void OnCollectDrawCalls(ref RenderContext renderContext)
{
if (renderContext.View.Pass == DrawPass.Depth)
return;
DragHandlers.CollectDrawCalls(_debugDrawData, ref renderContext);
if (ShowNavigation)
Editor.Internal_DrawNavMesh();
@@ -473,7 +471,13 @@ namespace FlaxEditor.Viewport
trans.SetRotation(ref world);
trans.Translation += world.TranslationVector;
}
obj.Transform = trans;
if (obj is ActorNode actorNode)
{
actorNode.Actor.Position = trans.Translation;
actorNode.Actor.Orientation = trans.Orientation;
}
else
obj.Transform = trans;
}
TransformGizmo.EndTransforming();
}
@@ -522,7 +526,9 @@ namespace FlaxEditor.Viewport
/// <param name="scaleDelta">The scale delta.</param>
public void ApplyTransform(List<SceneGraphNode> selection, ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta)
{
bool applyTranslation = !translationDelta.IsZero;
bool applyRotation = !rotationDelta.IsIdentity;
bool applyScale = !scaleDelta.IsZero;
bool useObjCenter = TransformGizmo.ActivePivot == TransformGizmoBase.PivotType.ObjectCenter;
Vector3 gizmoPosition = TransformGizmo.Position;
@@ -557,13 +563,29 @@ namespace FlaxEditor.Viewport
}
// Apply scale
const float scaleLimit = 99_999_999.0f;
trans.Scale = Float3.Clamp(trans.Scale + scaleDelta, new Float3(-scaleLimit), new Float3(scaleLimit));
if (applyScale)
{
const float scaleLimit = 99_999_999.0f;
trans.Scale = Float3.Clamp(trans.Scale + scaleDelta, new Float3(-scaleLimit), new Float3(scaleLimit)); ;
}
// Apply translation
trans.Translation += translationDelta;
if (applyTranslation)
{
trans.Translation += translationDelta;
}
obj.Transform = trans;
if (obj is ActorNode actorNode)
{
if (applyTranslation)
actorNode.Actor.Position = trans.Translation;
if (applyRotation)
actorNode.Actor.Orientation = trans.Orientation;
if (applyScale)
actorNode.Actor.Scale = trans.Scale;
}
else
obj.Transform = trans;
}
}
@@ -622,12 +644,12 @@ namespace FlaxEditor.Viewport
private static bool ValidateDragActorType(ScriptType actorType)
{
return Level.IsAnySceneLoaded && Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
return Level.IsAnySceneLoaded;
}
private static bool ValidateDragScriptItem(ScriptItem script)
{
return Level.IsAnySceneLoaded && Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
}
/// <inheritdoc />

View File

@@ -98,6 +98,7 @@ namespace FlaxEditor.Viewport
ShowDebugDraw = true;
ShowEditorPrimitives = true;
Gizmos = new GizmosCollection(this);
var inputOptions = window.Editor.Options.Options.Input;
// Prepare rendering task
Task.ActorsSource = ActorsSources.CustomActors;
@@ -218,8 +219,6 @@ namespace FlaxEditor.Viewport
private void OnCollectDrawCalls(ref RenderContext renderContext)
{
if (renderContext.View.Pass == DrawPass.Depth)
return;
DragHandlers.CollectDrawCalls(_debugDrawData, ref renderContext);
_debugDrawData.OnDraw(ref renderContext);
}
@@ -358,7 +357,9 @@ namespace FlaxEditor.Viewport
/// <param name="scaleDelta">The scale delta.</param>
public void ApplyTransform(List<SceneGraphNode> selection, ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta)
{
bool applyTranslation = !translationDelta.IsZero;
bool applyRotation = !rotationDelta.IsIdentity;
bool applyScale = !scaleDelta.IsZero;
bool useObjCenter = TransformGizmo.ActivePivot == TransformGizmoBase.PivotType.ObjectCenter;
Vector3 gizmoPosition = TransformGizmo.Position;
@@ -388,13 +389,29 @@ namespace FlaxEditor.Viewport
}
// Apply scale
const float scaleLimit = 99_999_999.0f;
trans.Scale = Float3.Clamp(trans.Scale + scaleDelta, new Float3(-scaleLimit), new Float3(scaleLimit));
if (applyScale)
{
const float scaleLimit = 99_999_999.0f;
trans.Scale = Float3.Clamp(trans.Scale + scaleDelta, new Float3(-scaleLimit), new Float3(scaleLimit));
}
// Apply translation
trans.Translation += translationDelta;
if (applyTranslation)
{
trans.Translation += translationDelta;
}
obj.Transform = trans;
if (obj is ActorNode actorNode)
{
if (applyTranslation)
actorNode.Actor.Position = trans.Translation;
if (applyRotation)
actorNode.Actor.Orientation = trans.Orientation;
if (applyScale)
actorNode.Actor.Scale = trans.Scale;
}
else
obj.Transform = trans;
}
}
@@ -499,7 +516,7 @@ namespace FlaxEditor.Viewport
private static bool ValidateDragActorType(ScriptType actorType)
{
return Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
return true;
}
private static bool ValidateDragScriptItem(ScriptItem script)

View File

@@ -459,7 +459,8 @@ namespace FlaxEditor.Windows.Assets
/// <returns>True if failed, otherwise false.</returns>
protected virtual bool SaveToOriginal()
{
if (_asset.LastLoadFailed)
// Wait until temporary asset file be fully loaded
if (_asset.WaitForLoaded())
{
Editor.LogError(string.Format("Cannot save asset {0}. Wait for temporary asset loaded failed.", _item.Path));
return true;
@@ -493,6 +494,12 @@ namespace FlaxEditor.Windows.Assets
return true;
}
// Reload original asset
if (originalAsset)
{
originalAsset.Reload();
}
// Refresh thumbnail
_item.RefreshThumbnail();

View File

@@ -302,17 +302,8 @@ namespace FlaxEditor.Windows.Assets
// TODO: improve the UI
layout.Space(40);
var addParamType = layout.ComboBox().ComboBox;
object lastValue = null;
foreach (var e in _proxy.DefaultValues)
lastValue = e.Value;
var allowedTypes = AllowedTypes.Select(CustomEditorsUtil.GetTypeNameUI).ToList();
int index = 0;
if (lastValue != null)
index = allowedTypes.FindIndex(x => x.Equals(CustomEditorsUtil.GetTypeNameUI(lastValue.GetType()), StringComparison.Ordinal));
addParamType.Items = allowedTypes;
addParamType.SelectedIndex = index;
addParamType.Items = AllowedTypes.Select(CustomEditorsUtil.GetTypeNameUI).ToList();
addParamType.SelectedIndex = 0;
_addParamType = addParamType;
var addParamButton = layout.Button("Add").Button;
addParamButton.Clicked += OnAddParamButtonClicked;

View File

@@ -355,6 +355,7 @@ namespace FlaxEditor.Windows.Assets
Editor.LogError("Failed to save surface data");
}
_asset.Reload();
_asset.WaitForLoaded();
}
}

View File

@@ -1,234 +0,0 @@
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
using FlaxEditor.Content;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.Windows.Assets
{
/// <summary>
/// Editor window to view video media.
/// </summary>
public sealed class VideoWindow : EditorWindow, IContentItemOwner
{
private VideoItem _item;
private Image _frame;
private VideoPlayer _videoPlayer;
private Image _seekBegin, _seekEnd, _seekLeft, _seekRight, _playPause, _stop;
/// <inheritdoc />
public VideoWindow(Editor editor, VideoItem item)
: base(editor, false, ScrollBars.None)
{
_item = item;
_item.AddReference(this);
Title = _item.ShortName;
// Setup video player
_videoPlayer = new VideoPlayer
{
PlayOnStart = false,
Url = item.Path,
};
// Setup UI
var style = Style.Current;
var icons = Editor.Icons;
var playbackButtonsSize = 24.0f;
var playbackButtonsMouseOverColor = Color.FromBgra(0xFFBBBBBB);
_frame = new Image
{
Brush = new VideoBrush(_videoPlayer),
AnchorPreset = AnchorPresets.StretchAll,
Offsets = new Margin(0.0f, 0.0f, 0.0f, playbackButtonsSize),
Parent = this,
};
var playbackButtonsArea = new ContainerControl
{
AutoFocus = false,
ClipChildren = false,
BackgroundColor = style.LightBackground,
AnchorPreset = AnchorPresets.HorizontalStretchBottom,
Offsets = new Margin(0, 0, -playbackButtonsSize, playbackButtonsSize),
Parent = this
};
var playbackButtonsPanel = new ContainerControl
{
AutoFocus = false,
ClipChildren = false,
AnchorPreset = AnchorPresets.VerticalStretchCenter,
Offsets = Margin.Zero,
Parent = playbackButtonsArea,
};
_seekBegin = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline start (Home)",
Brush = new SpriteBrush(icons.Skip64),
MouseOverColor = playbackButtonsMouseOverColor,
Rotation = 180.0f,
Parent = playbackButtonsPanel
};
_seekBegin.Clicked += (image, button) => SeekBegin();
playbackButtonsPanel.Width += playbackButtonsSize;
_seekLeft = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame back (Left Arrow)",
Brush = new SpriteBrush(icons.Left32),
MouseOverColor = playbackButtonsMouseOverColor,
Parent = playbackButtonsPanel
};
_seekLeft.Clicked += (image, button) => SeekLeft();
playbackButtonsPanel.Width += playbackButtonsSize;
_stop = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Stop playback",
Brush = new SpriteBrush(icons.Stop64),
MouseOverColor = playbackButtonsMouseOverColor,
Parent = playbackButtonsPanel
};
_stop.Clicked += (image, button) => Stop();
playbackButtonsPanel.Width += playbackButtonsSize;
_playPause = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Play/pause playback (Space)",
Brush = new SpriteBrush(icons.Play64),
MouseOverColor = playbackButtonsMouseOverColor,
Parent = playbackButtonsPanel
};
_playPause.Clicked += (image, button) => PlayPause();
playbackButtonsPanel.Width += playbackButtonsSize;
_seekRight = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Move one frame forward (Right Arrow)",
Brush = new SpriteBrush(icons.Right32),
MouseOverColor = playbackButtonsMouseOverColor,
Parent = playbackButtonsPanel
};
_seekRight.Clicked += (image, button) => SeekRight();
playbackButtonsPanel.Width += playbackButtonsSize;
_seekEnd = new Image(playbackButtonsPanel.Width, 0, playbackButtonsSize, playbackButtonsSize)
{
TooltipText = "Rewind to timeline end (End)",
Brush = new SpriteBrush(icons.Skip64),
MouseOverColor = playbackButtonsMouseOverColor,
Parent = playbackButtonsPanel
};
_seekEnd.Clicked += (image, button) => SeekEnd();
playbackButtonsPanel.Width += playbackButtonsSize;
playbackButtonsPanel.X = (playbackButtonsPanel.Parent.Width - playbackButtonsPanel.Width) * 0.5f;
}
private void PlayPause()
{
if (_videoPlayer.State == VideoPlayer.States.Playing)
_videoPlayer.Pause();
else
_videoPlayer.Play();
}
private void Stop()
{
_videoPlayer.Stop();
}
private void SeekBegin()
{
_videoPlayer.Time = 0.0f;
}
private void SeekEnd()
{
_videoPlayer.Time = _videoPlayer.Duration;
}
private void SeekLeft()
{
if (_videoPlayer.State == VideoPlayer.States.Paused)
_videoPlayer.Time -= 1.0f / _videoPlayer.FrameRate;
}
private void SeekRight()
{
if (_videoPlayer.State == VideoPlayer.States.Paused)
_videoPlayer.Time += 1.0f / _videoPlayer.FrameRate;
}
/// <inheritdoc />
public override bool OnKeyDown(KeyboardKeys key)
{
if (base.OnKeyDown(key))
return true;
switch (key)
{
case KeyboardKeys.ArrowLeft:
SeekLeft();
return true;
case KeyboardKeys.ArrowRight:
SeekRight();
return true;
case KeyboardKeys.Home:
SeekBegin();
return true;
case KeyboardKeys.End:
SeekEnd();
return true;
case KeyboardKeys.Spacebar:
PlayPause();
return true;
}
return false;
}
/// <inheritdoc />
public override void Update(float deltaTime)
{
base.Update(deltaTime);
// Update UI
var state = _videoPlayer.State;
var icons = Editor.Icons;
_stop.Enabled = state != VideoPlayer.States.Stopped;
_seekLeft.Enabled = _seekRight.Enabled = state != VideoPlayer.States.Playing;
((SpriteBrush)_playPause.Brush).Sprite = state == VideoPlayer.States.Playing ? icons.Pause64 : icons.Play64;
}
/// <inheritdoc />
public override void OnDestroy()
{
if (IsDisposing)
return;
_videoPlayer.Stop();
Object.Destroy(ref _videoPlayer);
_item.RemoveReference(this);
_item = null;
base.OnDestroy();
}
/// <inheritdoc />
public void OnItemDeleted(ContentItem item)
{
if (item == _item)
Close();
}
/// <inheritdoc />
public void OnItemRenamed(ContentItem item)
{
}
/// <inheritdoc />
public void OnItemReimported(ContentItem item)
{
}
/// <inheritdoc />
public void OnItemDispose(ContentItem item)
{
if (item == _item)
Close();
}
}
}

View File

@@ -311,23 +311,6 @@ namespace FlaxEditor.Windows
{
if (selection[i] is BinaryAssetItem binaryAssetItem)
Editor.ContentImporting.Reimport(binaryAssetItem);
else if (selection[i] is PrefabItem prefabItem)
{
var prefab = FlaxEngine.Content.Load<Prefab>(prefabItem.ID);
var modelPrefab = prefab.GetDefaultInstance().GetScript<ModelPrefab>();
if (!modelPrefab)
continue;
var importPath = modelPrefab.ImportPath;
var editor = Editor.Instance;
if (editor.ContentImporting.GetReimportPath("Model Prefab", ref importPath))
continue;
var folder = editor.ContentDatabase.Find(Path.GetDirectoryName(prefab.Path)) as ContentFolder;
if (folder == null)
continue;
var importOptions = modelPrefab.ImportOptions;
importOptions.Type = FlaxEngine.Tools.ModelTool.ModelType.Prefab;
editor.ContentImporting.Import(importPath, folder, true, importOptions);
}
}
}

View File

@@ -542,8 +542,6 @@ namespace FlaxEditor.Windows
return;
}
newShortName = newShortName.Trim();
// Cache data
string extension = item.IsFolder ? "" : Path.GetExtension(item.Path);
var newPath = StringUtils.CombinePaths(item.ParentFolder.Path, newShortName + extension);

View File

@@ -318,7 +318,6 @@ namespace FlaxEditor.Windows
{
Title = "Debug Log";
Icon = IconInfo;
OnEditorOptionsChanged(Editor.Options.Options);
FlaxEditor.Utilities.Utils.SetupCommonInputActions(this);
// Toolstrip
@@ -327,14 +326,42 @@ namespace FlaxEditor.Windows
Parent = this,
};
toolstrip.AddButton("Clear", Clear).LinkTooltip("Clears all log entries");
_clearOnPlayButton = (ToolStripButton)toolstrip.AddButton("Clear on Play").SetAutoCheck(true).SetChecked(true).LinkTooltip("Clears all log entries on enter playmode");
_collapseLogsButton = (ToolStripButton)toolstrip.AddButton("Collapse").SetAutoCheck(true).SetChecked(true).LinkTooltip("Collapses similar logs.");
_pauseOnErrorButton = (ToolStripButton)toolstrip.AddButton("Pause on Error").SetAutoCheck(true).LinkTooltip("Performs auto pause on error");
_clearOnPlayButton = (ToolStripButton)toolstrip.AddButton("Clear on Play", () =>
{
editor.Options.Options.Interface.DebugLogClearOnPlay = _clearOnPlayButton.Checked;
editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Clears all log entries on enter playmode");
_collapseLogsButton = (ToolStripButton)toolstrip.AddButton("Collapse", () =>
{
editor.Options.Options.Interface.DebugLogCollapse = _collapseLogsButton.Checked;
editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Collapses similar logs.");
_pauseOnErrorButton = (ToolStripButton)toolstrip.AddButton("Pause on Error", () =>
{
editor.Options.Options.Interface.DebugLogPauseOnError = _pauseOnErrorButton.Checked;
editor.Options.Apply(editor.Options.Options);
}).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.Error32, () =>
{
UpdateLogTypeVisibility(LogGroup.Error, _groupButtons[0].Checked);
editor.Options.Options.Interface.DebugLogShowErrorMessages = _groupButtons[0].Checked;
editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Shows/hides error messages");
_groupButtons[1] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Warning32, () =>
{
UpdateLogTypeVisibility(LogGroup.Warning, _groupButtons[1].Checked);
editor.Options.Options.Interface.DebugLogShowWarningMessages = _groupButtons[1].Checked;
editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Shows/hides warning messages");
_groupButtons[2] = (ToolStripButton)toolstrip.AddButton(editor.Icons.Info32, () =>
{
UpdateLogTypeVisibility(LogGroup.Info, _groupButtons[2].Checked);
editor.Options.Options.Interface.DebugLogShowInfoMessages = _groupButtons[2].Checked;
editor.Options.Apply(editor.Options.Options);
}).SetAutoCheck(true).LinkTooltip("Shows/hides info messages");
UpdateCount();
OnEditorOptionsChanged(Editor.Options.Options);
// Split panel
_split = new SplitPanel(Orientation.Vertical, ScrollBars.Vertical, ScrollBars.Both)
@@ -380,6 +407,12 @@ namespace FlaxEditor.Windows
private void OnEditorOptionsChanged(EditorOptions options)
{
_timestampsFormats = options.Interface.DebugLogTimestampsFormat;
_clearOnPlayButton.Checked = options.Interface.DebugLogClearOnPlay;
_collapseLogsButton.Checked = options.Interface.DebugLogCollapse;
_pauseOnErrorButton.Checked = options.Interface.DebugLogPauseOnError;
_groupButtons[0].Checked = options.Interface.DebugLogShowErrorMessages;
_groupButtons[1].Checked = options.Interface.DebugLogShowWarningMessages;
_groupButtons[2].Checked = options.Interface.DebugLogShowInfoMessages;
}
/// <summary>

View File

@@ -162,7 +162,7 @@ namespace FlaxEditor.Windows
Editor.Options.Apply(_options);
ClearDirtyFlag();
GatherData();
}
private void SetupCustomTabs()
@@ -234,6 +234,18 @@ namespace FlaxEditor.Windows
base.OnDestroy();
}
/// <inheritdoc />
protected override void OnShow()
{
if (!_isDataDirty)
{
// Refresh the data, skip when data is modified during window docking
GatherData();
}
base.OnShow();
}
/// <inheritdoc />
protected override bool OnClosing(ClosingReason reason)
{

View File

@@ -767,6 +767,13 @@ namespace FlaxEditor.Windows
Platform = BuildPlatform.Windows64,
Mode = BuildConfiguration.Development,
},
new BuildTarget
{
Name = "Windows 32bit",
Output = "Output\\Win32",
Platform = BuildPlatform.Windows32,
Mode = BuildConfiguration.Development,
},
}
};
_data = presets;
@@ -786,9 +793,9 @@ namespace FlaxEditor.Windows
Array.Copy(_data[_selectedPresetIndex].Targets, targets, count);
targets[count] = new BuildTarget
{
Name = "Windows 64bit",
Output = "Output\\Win64",
Platform = BuildPlatform.Windows64,
Name = "Xbox One",
Output = "Output\\XboxOne",
Platform = BuildPlatform.XboxOne,
Mode = BuildConfiguration.Development,
};
_data[_selectedPresetIndex].Targets = targets;

View File

@@ -470,10 +470,6 @@ namespace FlaxEditor.Windows
IsMaximized = false;
IsBorderless = false;
Cursor = CursorType.Default;
Screen.CursorLock = CursorLockMode.None;
if (Screen.MainWindow.IsMouseTracking)
Screen.MainWindow.EndTrackingMouse();
RootControl.GameRoot.EndMouseCapture();
}
/// <inheritdoc />
@@ -482,7 +478,7 @@ namespace FlaxEditor.Windows
base.OnMouseLeave();
// Remove focus from game window when mouse moves out and the cursor is hidden during game
if (ContainsFocus && Parent != null && Editor.IsPlayMode && !Screen.CursorVisible && Screen.CursorLock == CursorLockMode.None)
if ((IsFocused || ContainsFocus) && Parent != null && Editor.IsPlayMode && !Screen.CursorVisible)
{
Parent.Focus();
}

View File

@@ -281,7 +281,7 @@ namespace FlaxEditor.Windows
if (IsLayoutLocked)
return;
_hScroll.Maximum = Mathf.Max(_output.TextSize.X, _hScroll.Minimum);
_hScroll.Maximum = _output.TextSize.X;
_vScroll.Maximum = Mathf.Max(_output.TextSize.Y - _output.Height, _vScroll.Minimum);
}

View File

@@ -526,7 +526,7 @@ namespace FlaxEditor.Windows.Profiler
}
row.Depth = e.Depth;
row.Width = _table.Width;
row.Visible = e.Depth < 2;
row.Visible = e.Depth < 10;
row.BackgroundColor = i % 2 == 0 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}

View File

@@ -370,7 +370,7 @@ namespace FlaxEditor.Windows.Profiler
}
row.Depth = e.Depth;
row.Width = _table.Width;
row.Visible = e.Depth < 3;
row.Visible = e.Depth < 13;
row.BackgroundColor = i % 2 == 0 ? rowColor2 : Color.Transparent;
row.Parent = _table;
}

View File

@@ -367,7 +367,6 @@ namespace FlaxEditor.Windows
var tree = new Tree(false)
{
AnchorPreset = AnchorPresets.HorizontalStretchTop,
Margin = new Margin(0, 0, 0, panel.ScrollBarsSize),
IsScrollable = true,
Parent = panel
};

View File

@@ -232,12 +232,12 @@ void BehaviorTree::OnScriptsReloadEnd()
Graph.Setup(this);
}
void BehaviorTree::GetReferences(Array<Guid>& assets, Array<String>& files) const
void BehaviorTree::GetReferences(Array<Guid>& output) const
{
// Base
BinaryAsset::GetReferences(assets, files);
BinaryAsset::GetReferences(output);
Graph.GetReferences(assets);
Graph.GetReferences(output);
// Extract refs from serialized nodes data
for (const BehaviorTreeGraphNode& n : Graph.Nodes)
@@ -246,7 +246,7 @@ void BehaviorTree::GetReferences(Array<Guid>& assets, Array<String>& files) cons
continue;
const Variant& data = n.Values[1];
if (data.Type == VariantType::Blob)
JsonAssetBase::GetReferences(StringAnsiView((char*)data.AsBlob.Data, data.AsBlob.Length), assets);
JsonAssetBase::GetReferences(StringAnsiView((char*)data.AsBlob.Data, data.AsBlob.Length), output);
}
}

View File

@@ -98,7 +98,7 @@ public:
// [BinaryAsset]
void OnScriptingDispose() override;
#if USE_EDITOR
void GetReferences(Array<Guid>& assets, Array<String>& files) const override;
void GetReferences(Array<Guid>& output) const override;
#endif
protected:

View File

@@ -3,6 +3,7 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using FlaxEngine.Interop;
namespace FlaxEngine
{

View File

@@ -102,8 +102,8 @@ void AnimGraphExecutor::ProcessAnimEvents(AnimGraphNode* node, bool loop, float
Swap(eventTimeMin, eventTimeMax);
}
}
const float eventTime = (float)(animPos / anim->Data.FramesPerSecond);
const float eventDeltaTime = (float)((animPos - animPrevPos) / anim->Data.FramesPerSecond);
const float eventTime = animPos / static_cast<float>(anim->Data.FramesPerSecond);
const float eventDeltaTime = (animPos - animPrevPos) / static_cast<float>(anim->Data.FramesPerSecond);
for (const auto& track : anim->Events)
{
for (const auto& k : track.Second.GetKeyframes())
@@ -211,7 +211,7 @@ float GetAnimSamplePos(float length, Animation* anim, float pos, float speed)
}
if (animPos < 0)
animPos = animLength + animPos;
animPos = (float)(animPos * anim->Data.FramesPerSecond);
animPos *= static_cast<float>(anim->Data.FramesPerSecond);
return animPos;
}
@@ -265,7 +265,7 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
float nestedAnimPrevPos = animPrevPos - nestedAnim.Time;
const float nestedAnimLength = nestedAnim.Anim->GetLength();
const float nestedAnimSpeed = nestedAnim.Speed * speed;
const float frameRateMatchScale = (float)(nestedAnimSpeed / anim->Data.FramesPerSecond);
const float frameRateMatchScale = nestedAnimSpeed / (float)anim->Data.FramesPerSecond;
nestedAnimPos = nestedAnimPos * frameRateMatchScale;
nestedAnimPrevPos = nestedAnimPrevPos * frameRateMatchScale;
GetAnimSamplePos(nestedAnim.Loop, nestedAnimLength, nestedAnim.StartTime, nestedAnimPrevPos, nestedAnimPos, nestedAnimPos, nestedAnimPrevPos);
@@ -363,7 +363,8 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
// Check if animation looped
if (animPos < animPrevPos)
{
const float endPos = (float)(anim->GetLength() * anim->Data.FramesPerSecond);
const float endPos = anim->GetLength() * static_cast<float>(anim->Data.FramesPerSecond);
const float timeToEnd = endPos - animPrevPos;
Transform rootBegin = refPose;
rootChannel.Evaluate(0, &rootBegin, false);
@@ -371,13 +372,16 @@ void AnimGraphExecutor::ProcessAnimation(AnimGraphImpulse* nodes, AnimGraphNode*
Transform rootEnd = refPose;
rootChannel.Evaluate(endPos, &rootEnd, false);
//rootChannel.Evaluate(animPos - timeToEnd, &rootNow, true);
// Complex motion calculation to preserve the looped movement
// (end - before + now - begin)
// It sums the motion since the last update to anim end and since the start to now
if (motionPosition)
srcNode.Translation = (rootEnd.Translation - rootBefore.Translation + rootNode.Translation - rootBegin.Translation) * motionPositionMask;
if (motionRotation)
srcNode.Orientation = (rootBefore.Orientation.Conjugated() * rootEnd.Orientation) * (rootBegin.Orientation.Conjugated() * rootNode.Orientation);
srcNode.Orientation = rootEnd.Orientation * rootBefore.Orientation.Conjugated() * (rootNode.Orientation * rootBegin.Orientation.Conjugated());
//srcNode.Orientation = Quaternion::Identity;
}
else
{
@@ -1161,21 +1165,21 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
const auto nodes = node->GetNodes(this);
const auto basePoseNodes = static_cast<AnimGraphImpulse*>(valueA.AsPointer);
const auto blendPoseNodes = static_cast<AnimGraphImpulse*>(valueB.AsPointer);
const auto& refNodes = _graph.BaseModel.Get()->GetNodes();
Transform t, basePoseTransform, blendPoseTransform, refTransform;
const auto& refrenceNodes = _graph.BaseModel.Get()->GetNodes();
Transform t, basePoseTransform, blendPoseTransform, refrenceTransform;
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{
basePoseTransform = basePoseNodes->Nodes[i];
blendPoseTransform = blendPoseNodes->Nodes[i];
refTransform = refNodes[i].LocalTransform;
refrenceTransform = refrenceNodes[i].LocalTransform;
// base + (blend - reference)
t.Translation = basePoseTransform.Translation + (blendPoseTransform.Translation - refTransform.Translation);
auto diff = Quaternion::Invert(refTransform.Orientation) * blendPoseTransform.Orientation;
// base + (blend - refrence) = transform
t.Translation = basePoseTransform.Translation + (blendPoseTransform.Translation - refrenceTransform.Translation);
auto diff = Quaternion::Invert(refrenceTransform.Orientation) * blendPoseTransform.Orientation;
t.Orientation = basePoseTransform.Orientation * diff;
t.Scale = basePoseTransform.Scale + (blendPoseTransform.Scale - refTransform.Scale);
t.Scale = basePoseTransform.Scale + (blendPoseTransform.Scale - refrenceTransform.Scale);
// Lerp base and transform
//lerp base and transform
Transform::Lerp(basePoseTransform, t, alpha, nodes->Nodes[i]);
}
Transform::Lerp(basePoseNodes->RootMotion, basePoseNodes->RootMotion + blendPoseNodes->RootMotion, alpha, nodes->RootMotion);

View File

@@ -75,16 +75,16 @@ bool SceneAnimation::SaveTimeline(const BytesContainer& data)
#if USE_EDITOR
void SceneAnimation::GetReferences(Array<Guid>& assets, Array<String>& files) const
void SceneAnimation::GetReferences(Array<Guid>& output) const
{
// Base
BinaryAsset::GetReferences(assets, files);
BinaryAsset::GetReferences(output);
for (int32 i = 0; i < Tracks.Count(); i++)
{
const auto& track = Tracks[i];
if (track.Asset)
assets.Add(track.Asset->GetID());
output.Add(track.Asset->GetID());
}
}

View File

@@ -464,7 +464,7 @@ public:
public:
// [BinaryAsset]
#if USE_EDITOR
void GetReferences(Array<Guid>& assets, Array<String>& files) const override;
void GetReferences(Array<Guid>& output) const override;
#endif
protected:

View File

@@ -148,6 +148,44 @@ void Audio::SetEnableHRTF(bool value)
AudioBackend::Listener::ReinitializeAll();
}
void Audio::OnAddListener(AudioListener* listener)
{
ASSERT(!Listeners.Contains(listener));
if (Listeners.Count() >= AUDIO_MAX_LISTENERS)
{
LOG(Error, "Unsupported amount of the audio listeners!");
return;
}
Listeners.Add(listener);
AudioBackend::Listener::OnAdd(listener);
}
void Audio::OnRemoveListener(AudioListener* listener)
{
if (!Listeners.Remove(listener))
{
AudioBackend::Listener::OnRemove(listener);
}
}
void Audio::OnAddSource(AudioSource* source)
{
ASSERT(!Sources.Contains(source));
Sources.Add(source);
AudioBackend::Source::OnAdd(source);
}
void Audio::OnRemoveSource(AudioSource* source)
{
if (!Sources.Remove(source))
{
AudioBackend::Source::OnRemove(source);
}
}
bool AudioService::Init()
{
PROFILE_CPU_NAMED("Audio.Init");

View File

@@ -97,4 +97,11 @@ public:
/// </summary>
/// <param name="value">The value.</param>
API_PROPERTY() static void SetEnableHRTF(bool value);
public:
static void OnAddListener(AudioListener* listener);
static void OnRemoveListener(AudioListener* listener);
static void OnAddSource(AudioSource* source);
static void OnRemoveSource(AudioSource* source);
};

View File

@@ -15,6 +15,7 @@ class AudioBackend
friend class AudioService;
public:
enum class FeatureFlags
{
None = 0,
@@ -25,37 +26,41 @@ public:
static AudioBackend* Instance;
private:
// Listener
virtual void Listener_Reset() = 0;
virtual void Listener_VelocityChanged(const Vector3& velocity) = 0;
virtual void Listener_TransformChanged(const Vector3& position, const Quaternion& orientation) = 0;
virtual void Listener_OnAdd(AudioListener* listener) = 0;
virtual void Listener_OnRemove(AudioListener* listener) = 0;
virtual void Listener_VelocityChanged(AudioListener* listener) = 0;
virtual void Listener_TransformChanged(AudioListener* listener) = 0;
virtual void Listener_ReinitializeAll() = 0;
// Source
virtual uint32 Source_Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler) = 0;
virtual void Source_Remove(uint32 sourceID) = 0;
virtual void Source_VelocityChanged(uint32 sourceID, const Vector3& velocity) = 0;
virtual void Source_TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation) = 0;
virtual void Source_VolumeChanged(uint32 sourceID, float volume) = 0;
virtual void Source_PitchChanged(uint32 sourceID, float pitch) = 0;
virtual void Source_PanChanged(uint32 sourceID, float pan) = 0;
virtual void Source_IsLoopingChanged(uint32 sourceID, bool loop) = 0;
virtual void Source_SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler) = 0;
virtual void Source_Play(uint32 sourceID) = 0;
virtual void Source_Pause(uint32 sourceID) = 0;
virtual void Source_Stop(uint32 sourceID) = 0;
virtual void Source_SetCurrentBufferTime(uint32 sourceID, float value) = 0;
virtual float Source_GetCurrentBufferTime(uint32 id) = 0;
virtual void Source_SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID) = 0;
virtual void Source_GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount) = 0;
virtual void Source_GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount) = 0;
virtual void Source_QueueBuffer(uint32 sourceID, uint32 bufferID) = 0;
virtual void Source_DequeueProcessedBuffers(uint32 sourceID) = 0;
virtual void Source_OnAdd(AudioSource* source) = 0;
virtual void Source_OnRemove(AudioSource* source) = 0;
virtual void Source_VelocityChanged(AudioSource* source) = 0;
virtual void Source_TransformChanged(AudioSource* source) = 0;
virtual void Source_VolumeChanged(AudioSource* source) = 0;
virtual void Source_PitchChanged(AudioSource* source) = 0;
virtual void Source_PanChanged(AudioSource* source) = 0;
virtual void Source_IsLoopingChanged(AudioSource* source) = 0;
virtual void Source_SpatialSetupChanged(AudioSource* source) = 0;
virtual void Source_ClipLoaded(AudioSource* source) = 0;
virtual void Source_Cleanup(AudioSource* source) = 0;
virtual void Source_Play(AudioSource* source) = 0;
virtual void Source_Pause(AudioSource* source) = 0;
virtual void Source_Stop(AudioSource* source) = 0;
virtual void Source_SetCurrentBufferTime(AudioSource* source, float value) = 0;
virtual float Source_GetCurrentBufferTime(const AudioSource* source) = 0;
virtual void Source_SetNonStreamingBuffer(AudioSource* source) = 0;
virtual void Source_GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount) = 0;
virtual void Source_GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount) = 0;
virtual void Source_QueueBuffer(AudioSource* source, uint32 bufferId) = 0;
virtual void Source_DequeueProcessedBuffers(AudioSource* source) = 0;
// Buffer
virtual uint32 Buffer_Create() = 0;
virtual void Buffer_Delete(uint32 bufferID) = 0;
virtual void Buffer_Write(uint32 bufferID, byte* samples, const AudioDataInfo& info) = 0;
virtual void Buffer_Delete(uint32 bufferId) = 0;
virtual void Buffer_Write(uint32 bufferId, byte* samples, const AudioDataInfo& info) = 0;
// Base
virtual const Char* Base_Name() = 0;
@@ -68,27 +73,35 @@ private:
virtual void Base_Dispose() = 0;
public:
virtual ~AudioBackend()
{
}
public:
class Listener
{
public:
FORCE_INLINE static void Reset()
FORCE_INLINE static void OnAdd(AudioListener* listener)
{
Instance->Listener_Reset();
Instance->Listener_OnAdd(listener);
}
FORCE_INLINE static void VelocityChanged(const Vector3& velocity)
FORCE_INLINE static void OnRemove(AudioListener* listener)
{
Instance->Listener_VelocityChanged(velocity);
Instance->Listener_OnRemove(listener);
}
FORCE_INLINE static void TransformChanged(const Vector3& position, const Quaternion& orientation)
FORCE_INLINE static void VelocityChanged(AudioListener* listener)
{
Instance->Listener_TransformChanged(position, orientation);
Instance->Listener_VelocityChanged(listener);
}
FORCE_INLINE static void TransformChanged(AudioListener* listener)
{
Instance->Listener_TransformChanged(listener);
}
FORCE_INLINE static void ReinitializeAll()
@@ -100,118 +113,130 @@ public:
class Source
{
public:
FORCE_INLINE static uint32 Add(const AudioDataInfo& format, const Vector3& position, const Quaternion& orientation, float volume, float pitch, float pan, bool loop, bool spatial, float attenuation, float minDistance, float doppler)
FORCE_INLINE static void OnAdd(AudioSource* source)
{
return Instance->Source_Add(format, position, orientation, volume, pitch, pan, loop, spatial, attenuation, minDistance, doppler);
Instance->Source_OnAdd(source);
}
FORCE_INLINE static void Remove(uint32 sourceID)
FORCE_INLINE static void OnRemove(AudioSource* source)
{
Instance->Source_Remove(sourceID);
Instance->Source_OnRemove(source);
}
FORCE_INLINE static void VelocityChanged(uint32 sourceID, const Vector3& velocity)
FORCE_INLINE static void VelocityChanged(AudioSource* source)
{
Instance->Source_VelocityChanged(sourceID, velocity);
Instance->Source_VelocityChanged(source);
}
FORCE_INLINE static void TransformChanged(uint32 sourceID, const Vector3& position, const Quaternion& orientation)
FORCE_INLINE static void TransformChanged(AudioSource* source)
{
Instance->Source_TransformChanged(sourceID, position, orientation);
Instance->Source_TransformChanged(source);
}
FORCE_INLINE static void VolumeChanged(uint32 sourceID, float volume)
FORCE_INLINE static void VolumeChanged(AudioSource* source)
{
Instance->Source_VolumeChanged(sourceID, volume);
Instance->Source_VolumeChanged(source);
}
FORCE_INLINE static void PitchChanged(uint32 sourceID, float pitch)
FORCE_INLINE static void PitchChanged(AudioSource* source)
{
Instance->Source_PitchChanged(sourceID, pitch);
Instance->Source_PitchChanged(source);
}
FORCE_INLINE static void PanChanged(uint32 sourceID, float pan)
FORCE_INLINE static void PanChanged(AudioSource* source)
{
Instance->Source_PanChanged(sourceID, pan);
Instance->Source_PanChanged(source);
}
FORCE_INLINE static void IsLoopingChanged(uint32 sourceID, bool loop)
FORCE_INLINE static void IsLoopingChanged(AudioSource* source)
{
Instance->Source_IsLoopingChanged(sourceID, loop);
Instance->Source_IsLoopingChanged(source);
}
FORCE_INLINE static void SpatialSetupChanged(uint32 sourceID, bool spatial, float attenuation, float minDistance, float doppler)
FORCE_INLINE static void SpatialSetupChanged(AudioSource* source)
{
Instance->Source_SpatialSetupChanged(sourceID, spatial, attenuation, minDistance, doppler);
Instance->Source_SpatialSetupChanged(source);
}
FORCE_INLINE static void Play(uint32 sourceID)
FORCE_INLINE static void ClipLoaded(AudioSource* source)
{
Instance->Source_Play(sourceID);
Instance->Source_ClipLoaded(source);
}
FORCE_INLINE static void Pause(uint32 sourceID)
FORCE_INLINE static void Cleanup(AudioSource* source)
{
Instance->Source_Pause(sourceID);
Instance->Source_Cleanup(source);
}
FORCE_INLINE static void Stop(uint32 sourceID)
FORCE_INLINE static void Play(AudioSource* source)
{
Instance->Source_Stop(sourceID);
Instance->Source_Play(source);
}
FORCE_INLINE static void SetCurrentBufferTime(uint32 sourceID, float value)
FORCE_INLINE static void Pause(AudioSource* source)
{
Instance->Source_SetCurrentBufferTime(sourceID, value);
Instance->Source_Pause(source);
}
FORCE_INLINE static float GetCurrentBufferTime(uint32 sourceID)
FORCE_INLINE static void Stop(AudioSource* source)
{
return Instance->Source_GetCurrentBufferTime(sourceID);
Instance->Source_Stop(source);
}
FORCE_INLINE static void SetNonStreamingBuffer(uint32 sourceID, uint32 bufferID)
FORCE_INLINE static void SetCurrentBufferTime(AudioSource* source, float value)
{
Instance->Source_SetNonStreamingBuffer(sourceID, bufferID);
Instance->Source_SetCurrentBufferTime(source, value);
}
FORCE_INLINE static void GetProcessedBuffersCount(uint32 sourceID, int32& processedBuffersCount)
FORCE_INLINE static float GetCurrentBufferTime(const AudioSource* source)
{
Instance->Source_GetProcessedBuffersCount(sourceID, processedBuffersCount);
return Instance->Source_GetCurrentBufferTime(source);
}
FORCE_INLINE static void GetQueuedBuffersCount(uint32 sourceID, int32& queuedBuffersCount)
FORCE_INLINE static void SetNonStreamingBuffer(AudioSource* source)
{
Instance->Source_GetQueuedBuffersCount(sourceID, queuedBuffersCount);
Instance->Source_SetNonStreamingBuffer(source);
}
FORCE_INLINE static void QueueBuffer(uint32 sourceID, uint32 bufferID)
FORCE_INLINE static void GetProcessedBuffersCount(AudioSource* source, int32& processedBuffersCount)
{
Instance->Source_QueueBuffer(sourceID, bufferID);
Instance->Source_GetProcessedBuffersCount(source, processedBuffersCount);
}
FORCE_INLINE static void DequeueProcessedBuffers(uint32 sourceID)
FORCE_INLINE static void GetQueuedBuffersCount(AudioSource* source, int32& queuedBuffersCount)
{
Instance->Source_DequeueProcessedBuffers(sourceID);
Instance->Source_GetQueuedBuffersCount(source, queuedBuffersCount);
}
FORCE_INLINE static void QueueBuffer(AudioSource* source, uint32 bufferId)
{
Instance->Source_QueueBuffer(source, bufferId);
}
FORCE_INLINE static void DequeueProcessedBuffers(AudioSource* source)
{
Instance->Source_DequeueProcessedBuffers(source);
}
};
class Buffer
{
public:
FORCE_INLINE static uint32 Create()
{
return Instance->Buffer_Create();
}
FORCE_INLINE static void Delete(uint32 bufferID)
FORCE_INLINE static void Delete(uint32 bufferId)
{
Instance->Buffer_Delete(bufferID);
Instance->Buffer_Delete(bufferId);
}
FORCE_INLINE static void Write(uint32 bufferID, byte* samples, const AudioDataInfo& info)
FORCE_INLINE static void Write(uint32 bufferId, byte* samples, const AudioDataInfo& info)
{
Instance->Buffer_Write(bufferID, samples, info);
Instance->Buffer_Write(bufferId, samples, info);
}
};

Some files were not shown because too many files have changed in this diff Show More