Merge remote-tracking branch 'upstream/master' into lowlevel-networking
This commit is contained in:
BIN
Content/Editor/IconsAtlas.flax
LFS
BIN
Content/Editor/IconsAtlas.flax
LFS
Binary file not shown.
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 1,
|
||||
"Build": 6219
|
||||
"Build": 6221
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",
|
||||
|
||||
10
README.md
10
README.md
@@ -42,6 +42,16 @@ Flax Visual Studio extension provides better programming workflow, C# scripts de
|
||||
* Compile Flax project (hit F7 or CTRL+Shift+B)
|
||||
* Run Flax (hit F5 key)
|
||||
|
||||
---
|
||||
|
||||
**Note**
|
||||
|
||||
If building on Windows to support Vulkan rendering, first install the Vulkan SDK then set an environment variable to provide the path to the SDK prior to running GenerateProjectFiles.bat:
|
||||
|
||||
set VULKAN_SDK=C:\VulkanSDK\version\
|
||||
|
||||
---
|
||||
|
||||
## Linux
|
||||
|
||||
* Install Visual Studio Code
|
||||
|
||||
@@ -68,6 +68,11 @@ namespace FlaxEditor.Content.Create
|
||||
/// </summary>
|
||||
InputSettings,
|
||||
|
||||
/// <summary>
|
||||
/// The streaming settings.
|
||||
/// </summary>
|
||||
StreamingSettings,
|
||||
|
||||
/// <summary>
|
||||
/// The Windows settings.
|
||||
/// </summary>
|
||||
@@ -116,6 +121,7 @@ namespace FlaxEditor.Content.Create
|
||||
typeof(LocalizationSettings),
|
||||
typeof(BuildSettings),
|
||||
typeof(InputSettings),
|
||||
typeof(StreamingSettings),
|
||||
typeof(WindowsPlatformSettings),
|
||||
typeof(UWPPlatformSettings),
|
||||
typeof(LinuxPlatformSettings),
|
||||
|
||||
@@ -283,6 +283,13 @@ namespace FlaxEditor.Content.Import
|
||||
[EditorOrder(250), VisibleIf("PreserveAlphaCoverage"), DefaultValue(0.5f), Tooltip("The reference value for the alpha coverage preserving.")]
|
||||
public float PreserveAlphaCoverageReference { get; set; } = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Texture group for streaming (negative if unused). See Streaming Settings.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(CustomEditors.Dedicated.TextureGroupEditor))]
|
||||
[EditorOrder(300), Tooltip("Texture group for streaming (negative if unused). See Streaming Settings.")]
|
||||
public int TextureGroup = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The sprites. Used to keep created sprites on sprite atlas reimport.
|
||||
/// </summary>
|
||||
@@ -305,6 +312,7 @@ namespace FlaxEditor.Content.Import
|
||||
public float PreserveAlphaCoverageReference;
|
||||
public float Scale;
|
||||
public int MaxSize;
|
||||
public int TextureGroup;
|
||||
public Int2 Size;
|
||||
public Rectangle[] SpriteAreas;
|
||||
public string[] SpriteNames;
|
||||
@@ -327,7 +335,8 @@ namespace FlaxEditor.Content.Import
|
||||
PreserveAlphaCoverageReference = PreserveAlphaCoverageReference,
|
||||
Scale = Scale,
|
||||
Size = Size,
|
||||
MaxSize = (int)MaxSize
|
||||
MaxSize = (int)MaxSize,
|
||||
TextureGroup = TextureGroup,
|
||||
};
|
||||
if (Sprites != null && Sprites.Count > 0)
|
||||
{
|
||||
@@ -362,6 +371,7 @@ namespace FlaxEditor.Content.Import
|
||||
PreserveAlphaCoverageReference = options.PreserveAlphaCoverageReference;
|
||||
Scale = options.Scale;
|
||||
MaxSize = ConvertMaxSize(options.MaxSize);
|
||||
TextureGroup = options.TextureGroup;
|
||||
Size = options.Size;
|
||||
if (options.SpriteAreas != null)
|
||||
{
|
||||
|
||||
@@ -108,6 +108,26 @@ namespace FlaxEditor.Content
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when user dags this item into editor viewport or scene tree node.
|
||||
/// </summary>
|
||||
/// <param name="context">The editor context (eg. editor viewport or scene tree node).</param>
|
||||
/// <returns>True if item can be dropped in, otherwise false.</returns>
|
||||
public virtual bool OnEditorDrag(object context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when user drops the item into editor viewport or scene tree node.
|
||||
/// </summary>
|
||||
/// <param name="context">The editor context (eg. editor viewport or scene tree node).</param>
|
||||
/// <returns>The spawned object.</returns>
|
||||
public virtual Actor OnEditorDrop(object context)
|
||||
{
|
||||
throw new NotSupportedException($"Asset {GetType()} doesn't support dropping into viewport.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool DrawShadow => true;
|
||||
|
||||
|
||||
@@ -103,14 +103,26 @@ namespace FlaxEditor.Content
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="Model"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class ModelAssetItem : BinaryAssetItem
|
||||
public class ModelItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ModelAssetItem(string path, ref Guid id, string typeName, Type type)
|
||||
public ModelItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new StaticModel { Model = FlaxEngine.Content.LoadAsync<Model>(ID) };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
@@ -142,14 +154,26 @@ namespace FlaxEditor.Content
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SkinnedModel"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
public class SkinnedModelAssetItem : BinaryAssetItem
|
||||
public class SkinnedModeItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public SkinnedModelAssetItem(string path, ref Guid id, string typeName, Type type)
|
||||
public SkinnedModeItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Model)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new AnimatedModel { SkinnedModel = FlaxEngine.Content.LoadAsync<SkinnedModel>(ID) };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace FlaxEditor.Content
|
||||
public JsonAssetItem(string path, Guid id, string typeName)
|
||||
: base(path, typeName, ref id)
|
||||
{
|
||||
_thumbnail = Editor.Instance.Icons.Document128;
|
||||
_thumbnail = Editor.Instance.Icons.Json128;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -21,6 +21,18 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return PrefabManager.SpawnPrefab(FlaxEngine.Content.LoadAsync<Prefab>(ID), null);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override ContentItemType ItemType => ContentItemType.Asset;
|
||||
|
||||
|
||||
@@ -538,6 +538,18 @@ namespace FlaxEditor.Content
|
||||
Editor.Instance.CodeEditing.ClearTypes();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return new ScriptType(typeof(Actor)).IsAssignableFrom(ScriptType) && ScriptType.CanCreateInstance;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return (Actor)ScriptType.CreateInstance();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override SpriteHandle DefaultThumbnail => Editor.Instance.Icons.VisualScript128;
|
||||
|
||||
|
||||
@@ -241,16 +241,13 @@ CreateAssetResult PreviewsCache::create(CreateAssetContext& context)
|
||||
IMPORT_SETUP(PreviewsCache, 4);
|
||||
|
||||
// Create texture header (custom data)
|
||||
TextureHeader header;
|
||||
header.Width = ASSETS_ICONS_ATLAS_SIZE;
|
||||
header.Height = ASSETS_ICONS_ATLAS_SIZE;
|
||||
header.Format = ASSETS_ICONS_ATLAS_FORMAT;
|
||||
header.IsSRGB = false;
|
||||
header.IsCubeMap = false;
|
||||
header.MipLevels = 1;
|
||||
header.NeverStream = true;
|
||||
header.Type = TextureFormatType::Unknown;
|
||||
context.Data.CustomData.Copy(&header);
|
||||
TextureHeader textureHeader;
|
||||
textureHeader.Width = ASSETS_ICONS_ATLAS_SIZE;
|
||||
textureHeader.Height = ASSETS_ICONS_ATLAS_SIZE;
|
||||
textureHeader.Format = ASSETS_ICONS_ATLAS_FORMAT;
|
||||
textureHeader.MipLevels = 1;
|
||||
textureHeader.NeverStream = true;
|
||||
context.Data.CustomData.Copy(&textureHeader);
|
||||
|
||||
// Create blank image (chunk 0)
|
||||
uint64 imageSize = CalculateTextureMemoryUsage(ASSETS_ICONS_ATLAS_FORMAT, ASSETS_ICONS_ATLAS_SIZE, ASSETS_ICONS_ATLAS_SIZE, 1);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using FlaxEditor.Content.Thumbnails;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEditor.Windows;
|
||||
@@ -11,11 +12,51 @@ using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="AudioClip"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
class AudioClipItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public AudioClipItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Audio)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new AudioSource { Clip = FlaxEngine.Content.LoadAsync<AudioClip>(ID) };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnBuildTooltipText(StringBuilder sb)
|
||||
{
|
||||
base.OnBuildTooltipText(sb);
|
||||
|
||||
var asset = FlaxEngine.Content.Load<AudioClip>(ID, 100);
|
||||
if (asset)
|
||||
{
|
||||
var info = asset.Info;
|
||||
sb.Append("Duration: ").Append(asset.Length).AppendLine();
|
||||
sb.Append("Channels: ").Append(info.NumChannels).AppendLine();
|
||||
sb.Append("Bit Depth: ").Append(info.BitDepth).AppendLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="AudioClip"/> asset proxy object.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
|
||||
public class AudioClipProxy : BinaryAssetProxy
|
||||
class AudioClipProxy : BinaryAssetProxy
|
||||
{
|
||||
private List<AudioClipPreview> _previews;
|
||||
|
||||
@@ -34,6 +75,12 @@ namespace FlaxEditor.Content
|
||||
return new AudioClipWindow(editor, (AssetItem)item);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
return new AudioClipItem(path, ref id, typeName, AssetType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0xB3452B);
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ namespace FlaxEditor.Content
|
||||
if (typeof(TextureBase).IsAssignableFrom(type))
|
||||
return new TextureAssetItem(path, ref id, typeName, type);
|
||||
if (typeof(Model).IsAssignableFrom(type))
|
||||
return new ModelAssetItem(path, ref id, typeName, type);
|
||||
return new ModelItem(path, ref id, typeName, type);
|
||||
if (typeof(SkinnedModel).IsAssignableFrom(type))
|
||||
return new SkinnedModelAssetItem(path, ref id, typeName, type);
|
||||
return new SkinnedModeItem(path, ref id, typeName, type);
|
||||
|
||||
ContentItemSearchFilter searchFilter;
|
||||
if (typeof(MaterialBase).IsAssignableFrom(type))
|
||||
@@ -58,11 +58,9 @@ namespace FlaxEditor.Content
|
||||
searchFilter = ContentItemSearchFilter.Prefab;
|
||||
else if (typeof(SceneAsset).IsAssignableFrom(type))
|
||||
searchFilter = ContentItemSearchFilter.Scene;
|
||||
else if (typeof(AudioClip).IsAssignableFrom(type))
|
||||
searchFilter = ContentItemSearchFilter.Audio;
|
||||
else if (typeof(Animation).IsAssignableFrom(type))
|
||||
searchFilter = ContentItemSearchFilter.Animation;
|
||||
else if (typeof(ParticleEmitter).IsAssignableFrom(type) || typeof(ParticleSystem).IsAssignableFrom(type))
|
||||
else if (typeof(ParticleEmitter).IsAssignableFrom(type))
|
||||
searchFilter = ContentItemSearchFilter.Particles;
|
||||
else
|
||||
searchFilter = ContentItemSearchFilter.Other;
|
||||
|
||||
@@ -8,11 +8,36 @@ using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="CollisionData"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
class CollisionDataItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public CollisionDataItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new MeshCollider { CollisionData = FlaxEngine.Content.LoadAsync<CollisionData>(ID) };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="CollisionData"/> asset proxy object.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetProxy" />
|
||||
public class CollisionDataProxy : BinaryAssetProxy
|
||||
class CollisionDataProxy : BinaryAssetProxy
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override string Name => "Collision Data";
|
||||
@@ -23,6 +48,12 @@ namespace FlaxEditor.Content
|
||||
return new CollisionDataWindow(editor, item as AssetItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
return new CollisionDataItem(path, ref id, typeName, AssetType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0x2c3e50);
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace FlaxEditor.Content
|
||||
!type.IsAbstract &&
|
||||
!type.IsGenericType &&
|
||||
type.Type.GetConstructor(Type.EmptyTypes) != null &&
|
||||
!typeof(FlaxEngine.GUI.Control).IsAssignableFrom(type.Type) &&
|
||||
!typeof(FlaxEngine.Object).IsAssignableFrom(type.Type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace FlaxEditor.Content
|
||||
|
||||
menu.AddButton("Create collision data", () =>
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(((ModelAssetItem)item).ID);
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(((ModelItem)item).ID);
|
||||
var collisionDataProxy = (CollisionDataProxy)Editor.Instance.ContentDatabase.GetProxy<CollisionData>();
|
||||
collisionDataProxy.CreateCollisionDataFromModel(model);
|
||||
});
|
||||
|
||||
@@ -10,6 +10,31 @@ using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="ParticleSystem"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
class ParticleSystemItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public ParticleSystemItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Particles)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new ParticleEffect { ParticleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(ID) };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="ParticleSystem"/> asset proxy object.
|
||||
/// </summary>
|
||||
@@ -28,6 +53,12 @@ namespace FlaxEditor.Content
|
||||
return new ParticleSystemWindow(editor, item as AssetItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
return new ParticleSystemItem(path, ref id, typeName, AssetType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0xFF790200);
|
||||
|
||||
|
||||
@@ -7,6 +7,31 @@ using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="BinaryAssetItem"/> for <see cref="SceneAnimation"/> assets.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Content.BinaryAssetItem" />
|
||||
class SceneAnimationItem : BinaryAssetItem
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public SceneAnimationItem(string path, ref Guid id, string typeName, Type type)
|
||||
: base(path, ref id, typeName, type, ContentItemSearchFilter.Other)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnEditorDrag(object context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Actor OnEditorDrop(object context)
|
||||
{
|
||||
return new SceneAnimationPlayer { Animation = FlaxEngine.Content.LoadAsync<SceneAnimation>(ID) };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A <see cref="SceneAnimation"/> asset proxy object.
|
||||
/// </summary>
|
||||
@@ -22,6 +47,12 @@ namespace FlaxEditor.Content
|
||||
return new SceneAnimationWindow(editor, item as AssetItem);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
return new SceneAnimationItem(path, ref id, typeName, AssetType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color AccentColor => Color.FromRGB(0xff5c4a87);
|
||||
|
||||
|
||||
@@ -136,6 +136,8 @@ public:
|
||||
String AssemblerArgs;
|
||||
String ArchiverPath;
|
||||
String ArchiverArgs;
|
||||
String AuxToolPath;
|
||||
String AuxToolArgs;
|
||||
String AotCachePath;
|
||||
Dictionary<String, String> EnvVars;
|
||||
Array<String> AssembliesSearchDirs;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "Engine/Core/Config/PlatformSettings.h"
|
||||
#include "Engine/Core/Config/GameSettings.h"
|
||||
#include "Engine/Core/Config/BuildSettings.h"
|
||||
#include "Engine/Streaming/StreamingSettings.h"
|
||||
#include "Engine/ShadersCompilation/ShadersCompilation.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Graphics/Textures/TextureData.h"
|
||||
@@ -44,6 +45,35 @@
|
||||
|
||||
Dictionary<String, CookAssetsStep::ProcessAssetFunc> CookAssetsStep::AssetProcessors;
|
||||
|
||||
bool CookAssetsStep::CacheEntry::IsValid(bool withDependencies)
|
||||
{
|
||||
AssetInfo assetInfo;
|
||||
if (Content::GetAssetInfo(ID, assetInfo))
|
||||
{
|
||||
if (TypeName == assetInfo.TypeName)
|
||||
{
|
||||
if (FileSystem::GetFileLastEditTime(assetInfo.Path) <= FileModified)
|
||||
{
|
||||
bool isValid = true;
|
||||
if (withDependencies)
|
||||
{
|
||||
for (auto& f : FileDependencies)
|
||||
{
|
||||
if (FileSystem::GetFileLastEditTime(f.First) > f.Second)
|
||||
{
|
||||
isValid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isValid)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
CookAssetsStep::CacheEntry& CookAssetsStep::CacheData::CreateEntry(const JsonAssetBase* asset, String& cachedFilePath)
|
||||
{
|
||||
ASSERT(asset->DataTypeName.HasChars());
|
||||
@@ -68,7 +98,6 @@ CookAssetsStep::CacheEntry& CookAssetsStep::CacheData::CreateEntry(const Asset*
|
||||
void CookAssetsStep::CacheData::InvalidateShaders()
|
||||
{
|
||||
LOG(Info, "Invalidating cached shader assets.");
|
||||
|
||||
for (auto e = Entries.Begin(); e.IsNotEnd(); ++e)
|
||||
{
|
||||
auto& typeName = e->Value.TypeName;
|
||||
@@ -83,6 +112,23 @@ void CookAssetsStep::CacheData::InvalidateShaders()
|
||||
}
|
||||
}
|
||||
|
||||
void CookAssetsStep::CacheData::InvalidateTextures()
|
||||
{
|
||||
LOG(Info, "Invalidating cached texture assets.");
|
||||
for (auto e = Entries.Begin(); e.IsNotEnd(); ++e)
|
||||
{
|
||||
auto& typeName = e->Value.TypeName;
|
||||
if (
|
||||
typeName == Texture::TypeName ||
|
||||
typeName == CubeTexture::TypeName ||
|
||||
typeName == SpriteAtlas::TypeName
|
||||
)
|
||||
{
|
||||
Entries.Remove(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
{
|
||||
HeaderFilePath = data.CacheDirectory / String::Format(TEXT("CookedHeader_{0}.bin"), FLAXENGINE_VERSION_BUILD);
|
||||
@@ -159,17 +205,17 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
Entries.Clear();
|
||||
}
|
||||
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
const auto gameSettings = GameSettings::Get();
|
||||
|
||||
// Invalidate shaders and assets with shaders if need to rebuild them
|
||||
bool invalidateShaders = false;
|
||||
const auto buildSettings = BuildSettings::Get();
|
||||
const bool shadersNoOptimize = buildSettings->ShadersNoOptimize;
|
||||
const bool shadersGenerateDebugData = buildSettings->ShadersGenerateDebugData;
|
||||
if (shadersNoOptimize != Settings.Global.ShadersNoOptimize)
|
||||
if (buildSettings->ShadersNoOptimize != Settings.Global.ShadersNoOptimize)
|
||||
{
|
||||
LOG(Info, "ShadersNoOptimize option has been modified.");
|
||||
invalidateShaders = true;
|
||||
}
|
||||
if (shadersGenerateDebugData != Settings.Global.ShadersGenerateDebugData)
|
||||
if (buildSettings->ShadersGenerateDebugData != Settings.Global.ShadersGenerateDebugData)
|
||||
{
|
||||
LOG(Info, "ShadersGenerateDebugData option has been modified.");
|
||||
invalidateShaders = true;
|
||||
@@ -218,6 +264,12 @@ void CookAssetsStep::CacheData::Load(CookingData& data)
|
||||
#endif
|
||||
if (invalidateShaders)
|
||||
InvalidateShaders();
|
||||
|
||||
// Invalidate textures if streaming settings gets modified
|
||||
if (Settings.Global.StreamingSettingsAssetId != gameSettings->Streaming || (Entries.ContainsKey(gameSettings->Streaming) && !Entries[gameSettings->Streaming].IsValid()))
|
||||
{
|
||||
InvalidateTextures();
|
||||
}
|
||||
}
|
||||
|
||||
void CookAssetsStep::CacheData::Save()
|
||||
@@ -541,91 +593,127 @@ bool ProcessParticleEmitter(CookAssetsStep::AssetCookData& data)
|
||||
bool ProcessTextureBase(CookAssetsStep::AssetCookData& data)
|
||||
{
|
||||
const auto asset = static_cast<TextureBase*>(data.Asset);
|
||||
|
||||
// Check if target platform doesn't support the texture format
|
||||
const auto& assetHeader = asset->StreamingTexture()->GetHeader();
|
||||
const auto format = asset->Format();
|
||||
const auto targetFormat = data.Data.Tools->GetTextureFormat(data.Data, asset, format);
|
||||
const auto streamingSettings = StreamingSettings::Get();
|
||||
int32 mipLevelsMax = GPU_MAX_TEXTURE_MIP_LEVELS;
|
||||
if (assetHeader->TextureGroup >= 0 && assetHeader->TextureGroup < streamingSettings->TextureGroups.Count())
|
||||
{
|
||||
auto& group = streamingSettings->TextureGroups[assetHeader->TextureGroup];
|
||||
mipLevelsMax = group.MipLevelsMax;
|
||||
group.MipLevelsMaxPerPlatform.TryGet(data.Data.Tools->GetPlatform(), mipLevelsMax);
|
||||
}
|
||||
|
||||
// Faster path if don't need to modify texture for the target platform
|
||||
if (format == targetFormat && assetHeader->MipLevels <= mipLevelsMax)
|
||||
{
|
||||
return CookAssetsStep::ProcessDefaultAsset(data);
|
||||
}
|
||||
|
||||
// Extract texture data from the asset
|
||||
TextureData textureDataSrc;
|
||||
auto assetLock = asset->LockData();
|
||||
if (asset->GetTextureData(textureDataSrc, false))
|
||||
{
|
||||
LOG(Error, "Failed to load data from texture {0}", asset->ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
TextureData* textureData = &textureDataSrc;
|
||||
TextureData textureDataTmp1;
|
||||
|
||||
if (format != targetFormat)
|
||||
{
|
||||
// Extract texture data from the asset
|
||||
TextureData textureData;
|
||||
auto assetLock = asset->LockData();
|
||||
if (asset->GetTextureData(textureData, false))
|
||||
{
|
||||
LOG(Error, "Failed to load data from texture {0}", asset->ToString());
|
||||
return true;
|
||||
}
|
||||
|
||||
// Convert texture data to the target format
|
||||
TextureData targetTextureData;
|
||||
if (TextureTool::Convert(targetTextureData, textureData, targetFormat))
|
||||
if (TextureTool::Convert(textureDataTmp1, *textureData, targetFormat))
|
||||
{
|
||||
LOG(Error, "Failed to convert texture {0} from format {1} to {2}", asset->ToString(), (int32)format, (int32)targetFormat);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Adjust texture header
|
||||
auto& header = *(TextureHeader*)data.InitData.CustomData.Get();
|
||||
header.Width = targetTextureData.Width;
|
||||
header.Height = targetTextureData.Height;
|
||||
header.Format = targetTextureData.Format;
|
||||
header.MipLevels = targetTextureData.GetMipLevels();
|
||||
|
||||
// Serialize texture data into the asset chunks
|
||||
for (int32 mipIndex = 0; mipIndex < targetTextureData.GetMipLevels(); mipIndex++)
|
||||
{
|
||||
auto chunk = New<FlaxChunk>();
|
||||
data.InitData.Header.Chunks[mipIndex] = chunk;
|
||||
|
||||
// Calculate the texture data storage layout
|
||||
uint32 rowPitch, slicePitch;
|
||||
const int32 mipWidth = Math::Max(1, targetTextureData.Width >> mipIndex);
|
||||
const int32 mipHeight = Math::Max(1, targetTextureData.Height >> mipIndex);
|
||||
RenderTools::ComputePitch(targetTextureData.Format, mipWidth, mipHeight, rowPitch, slicePitch);
|
||||
chunk->Data.Allocate(slicePitch * targetTextureData.GetArraySize());
|
||||
|
||||
// Copy array slices into mip data (sequential)
|
||||
for (int32 arrayIndex = 0; arrayIndex < targetTextureData.Items.Count(); arrayIndex++)
|
||||
{
|
||||
auto& mipData = targetTextureData.Items[arrayIndex].Mips[mipIndex];
|
||||
byte* src = mipData.Data.Get();
|
||||
byte* dst = chunk->Data.Get() + (slicePitch * arrayIndex);
|
||||
|
||||
// Faster path if source and destination data layout matches
|
||||
if (rowPitch == mipData.RowPitch && slicePitch == mipData.DepthPitch)
|
||||
{
|
||||
Platform::MemoryCopy(dst, src, slicePitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto copyRowSize = Math::Min(mipData.RowPitch, rowPitch);
|
||||
for (uint32 line = 0; line < mipData.Lines; line++)
|
||||
{
|
||||
Platform::MemoryCopy(dst, src, copyRowSize);
|
||||
src += mipData.RowPitch;
|
||||
dst += rowPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone any custom asset chunks (eg. sprite atlas data, mips are in 0-13 chunks)
|
||||
for (int32 i = 14; i < ASSET_FILE_DATA_CHUNKS; i++)
|
||||
{
|
||||
const auto chunk = asset->GetChunk(i);
|
||||
if (chunk != nullptr && chunk->IsMissing() && chunk->ExistsInFile())
|
||||
{
|
||||
if (asset->Storage->LoadAssetChunk(chunk))
|
||||
return true;
|
||||
data.InitData.Header.Chunks[i] = chunk->Clone();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
textureData = &textureDataSrc;
|
||||
}
|
||||
|
||||
// Fallback to the default asset processing
|
||||
return CookAssetsStep::ProcessDefaultAsset(data);
|
||||
if (assetHeader->MipLevels > mipLevelsMax)
|
||||
{
|
||||
// Reduce texture quality
|
||||
const int32 mipLevelsToStrip = assetHeader->MipLevels - mipLevelsMax;
|
||||
textureData->Width = Math::Max(1, textureData->Width >> mipLevelsToStrip);
|
||||
textureData->Height = Math::Max(1, textureData->Height >> mipLevelsToStrip);
|
||||
textureData->Depth = Math::Max(1, textureData->Depth >> mipLevelsToStrip);
|
||||
for (int32 arrayIndex = 0; arrayIndex < textureData->Items.Count(); arrayIndex++)
|
||||
{
|
||||
auto& item = textureData->Items[arrayIndex];
|
||||
Array<TextureMipData, FixedAllocation<GPU_MAX_TEXTURE_MIP_LEVELS>> oldMips(MoveTemp(item.Mips));
|
||||
item.Mips.Resize(mipLevelsMax);
|
||||
for (int32 mipIndex = 0; mipIndex < mipLevelsMax; mipIndex++)
|
||||
{
|
||||
auto& dstMip = item.Mips[mipIndex];
|
||||
auto& srcMip = oldMips[mipIndex + mipLevelsToStrip];
|
||||
dstMip = MoveTemp(srcMip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adjust texture header
|
||||
auto& header = *(TextureHeader*)data.InitData.CustomData.Get();
|
||||
header.Width = textureData->Width;
|
||||
header.Height = textureData->Height;
|
||||
header.Depth = textureData->Depth;
|
||||
header.Format = textureData->Format;
|
||||
header.MipLevels = textureData->GetMipLevels();
|
||||
|
||||
// Serialize texture data into the asset chunks
|
||||
for (int32 mipIndex = 0; mipIndex < textureData->GetMipLevels(); mipIndex++)
|
||||
{
|
||||
auto chunk = New<FlaxChunk>();
|
||||
data.InitData.Header.Chunks[mipIndex] = chunk;
|
||||
|
||||
// Calculate the texture data storage layout
|
||||
uint32 rowPitch, slicePitch;
|
||||
const int32 mipWidth = Math::Max(1, textureData->Width >> mipIndex);
|
||||
const int32 mipHeight = Math::Max(1, textureData->Height >> mipIndex);
|
||||
RenderTools::ComputePitch(textureData->Format, mipWidth, mipHeight, rowPitch, slicePitch);
|
||||
chunk->Data.Allocate(slicePitch * textureData->GetArraySize());
|
||||
|
||||
// Copy array slices into mip data (sequential)
|
||||
for (int32 arrayIndex = 0; arrayIndex < textureData->Items.Count(); arrayIndex++)
|
||||
{
|
||||
auto& mipData = textureData->Items[arrayIndex].Mips[mipIndex];
|
||||
byte* src = mipData.Data.Get();
|
||||
byte* dst = chunk->Data.Get() + (slicePitch * arrayIndex);
|
||||
|
||||
// Faster path if source and destination data layout matches
|
||||
if (rowPitch == mipData.RowPitch && slicePitch == mipData.DepthPitch)
|
||||
{
|
||||
Platform::MemoryCopy(dst, src, slicePitch);
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto copyRowSize = Math::Min(mipData.RowPitch, rowPitch);
|
||||
for (uint32 line = 0; line < mipData.Lines; line++)
|
||||
{
|
||||
Platform::MemoryCopy(dst, src, copyRowSize);
|
||||
src += mipData.RowPitch;
|
||||
dst += rowPitch;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone any custom asset chunks (eg. sprite atlas data, mips are in 0-13 chunks)
|
||||
for (int32 i = 14; i < ASSET_FILE_DATA_CHUNKS; i++)
|
||||
{
|
||||
const auto chunk = asset->GetChunk(i);
|
||||
if (chunk != nullptr && chunk->IsMissing() && chunk->ExistsInFile())
|
||||
{
|
||||
if (asset->Storage->LoadAssetChunk(chunk))
|
||||
return true;
|
||||
data.InitData.Header.Chunks[i] = chunk->Clone();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
CookAssetsStep::CookAssetsStep()
|
||||
@@ -938,6 +1026,7 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
cache.Settings.Global.ShadersNoOptimize = buildSettings->ShadersNoOptimize;
|
||||
cache.Settings.Global.ShadersGenerateDebugData = buildSettings->ShadersGenerateDebugData;
|
||||
cache.Settings.Global.StreamingSettingsAssetId = gameSettings->Streaming;
|
||||
}
|
||||
|
||||
// Note: this step converts all the assets (even the json) into the binary files (FlaxStorage format).
|
||||
|
||||
@@ -49,6 +49,8 @@ public:
|
||||
/// The list of files on which this entry depends on. Cached date is the last edit time used to discard cache result on modification.
|
||||
/// </summary>
|
||||
FileDependenciesList FileDependencies;
|
||||
|
||||
bool IsValid(bool withDependencies = false);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -93,6 +95,7 @@ public:
|
||||
{
|
||||
bool ShadersNoOptimize;
|
||||
bool ShadersGenerateDebugData;
|
||||
Guid StreamingSettingsAssetId;
|
||||
} Global;
|
||||
} Settings;
|
||||
|
||||
@@ -134,6 +137,11 @@ public:
|
||||
/// </summary>
|
||||
void InvalidateShaders();
|
||||
|
||||
/// <summary>
|
||||
/// Removes all cached entries for assets that contain a texture. This forces rebuild for them.
|
||||
/// </summary>
|
||||
void InvalidateTextures();
|
||||
|
||||
/// <summary>
|
||||
/// Loads the cache for the given cooking data.
|
||||
/// </summary>
|
||||
|
||||
@@ -142,6 +142,10 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
public void RebuildLayout()
|
||||
{
|
||||
// Skip rebuilding during init
|
||||
if (CurrentCustomEditor == this)
|
||||
return;
|
||||
|
||||
// Special case for root objects to run normal layout build
|
||||
if (_presenter.Selection == Values)
|
||||
{
|
||||
@@ -789,8 +793,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <returns>True if allow to handle this event, otherwise false.</returns>
|
||||
protected virtual bool OnDirty(CustomEditor editor, object value, object token = null)
|
||||
{
|
||||
ParentEditor.OnDirty(editor, value, token);
|
||||
return true;
|
||||
return ParentEditor.OnDirty(editor, value, token);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -68,19 +68,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var cm = new ItemsListContextMenu(180);
|
||||
for (int i = 0; i < scripts.Count; i++)
|
||||
{
|
||||
var scriptType = scripts[i];
|
||||
var item = new ItemsListContextMenu.Item(scriptType.Name, scriptType)
|
||||
{
|
||||
TooltipText = scriptType.TypeName,
|
||||
};
|
||||
var attributes = scriptType.GetAttributes(false);
|
||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
||||
if (tooltipAttribute != null)
|
||||
{
|
||||
item.TooltipText += '\n';
|
||||
item.TooltipText += tooltipAttribute.Text;
|
||||
}
|
||||
cm.AddItem(item);
|
||||
cm.AddItem(new TypeSearchPopup.TypeItemView(scripts[i]));
|
||||
}
|
||||
cm.ItemClicked += item => AddScript((ScriptType)item.Tag);
|
||||
cm.SortChildren();
|
||||
|
||||
51
Source/Editor/CustomEditors/Dedicated/TextureGroupEditor.cs
Normal file
51
Source/Editor/CustomEditors/Dedicated/TextureGroupEditor.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEditor.GUI;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="TextureGroup"/> index.
|
||||
/// </summary>
|
||||
internal class TextureGroupEditor : CustomEditor
|
||||
{
|
||||
private ComboBoxElement _element;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_element = layout.ComboBox();
|
||||
_element.ComboBox.SelectedIndexChanged += OnSelectedIndexChanged;
|
||||
_element.ComboBox.AddItem("None");
|
||||
var groups = GameSettings.Load<StreamingSettings>();
|
||||
if (groups?.TextureGroups != null)
|
||||
{
|
||||
for (int i = 0; i < groups.TextureGroups.Length; i++)
|
||||
{
|
||||
_element.ComboBox.AddItem(groups.TextureGroups[i].Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectedIndexChanged(ComboBox comboBox)
|
||||
{
|
||||
var value = comboBox.HasSelection ? comboBox.SelectedIndex - 1 : -1;
|
||||
SetValue(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
var value = (int)Values[0];
|
||||
_element.ComboBox.SelectedIndex = value + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,6 +412,11 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_cachedType = null;
|
||||
if (HasDifferentTypes)
|
||||
{
|
||||
// TODO: support stable editing multiple different control types (via generic way or for transform-only)
|
||||
return;
|
||||
}
|
||||
|
||||
// Set control type button
|
||||
var space = layout.Space(20);
|
||||
@@ -600,34 +605,26 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private bool _cachedXEq;
|
||||
private bool _cachedYEq;
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes if equality of anchors does not correspond to the cached equality
|
||||
/// </summary>
|
||||
public void RefreshBaseOnAnchorsEquality()
|
||||
{
|
||||
if (Values.HasNull)
|
||||
return;
|
||||
|
||||
GetAnchorEquality(out bool xEq, out bool yEq, ValuesTypes);
|
||||
if (xEq != _cachedXEq || yEq != _cachedYEq)
|
||||
{
|
||||
RebuildLayout();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
// Automatic layout rebuild if control type gets changed
|
||||
var type = Values.HasNull ? null : Values[0].GetType();
|
||||
if (type != _cachedType)
|
||||
if (_cachedType != null)
|
||||
{
|
||||
RebuildLayout();
|
||||
return;
|
||||
// Automatic layout rebuild if control type gets changed
|
||||
var type = Values.HasNull ? null : Values[0].GetType();
|
||||
if (type != _cachedType)
|
||||
{
|
||||
RebuildLayout();
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh anchors
|
||||
GetAnchorEquality(out bool xEq, out bool yEq, ValuesTypes);
|
||||
if (xEq != _cachedXEq || yEq != _cachedYEq)
|
||||
{
|
||||
RebuildLayout();
|
||||
}
|
||||
}
|
||||
RefreshBaseOnAnchorsEquality();
|
||||
//RefreshValues();
|
||||
|
||||
base.Refresh();
|
||||
}
|
||||
@@ -642,59 +639,39 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var cm = new ItemsListContextMenu(180);
|
||||
for (int i = 0; i < controlTypes.Count; i++)
|
||||
{
|
||||
var controlType = controlTypes[i];
|
||||
var item = new ItemsListContextMenu.Item(controlType.Name, controlType)
|
||||
{
|
||||
TooltipText = controlType.TypeName,
|
||||
};
|
||||
var attributes = controlType.GetAttributes(false);
|
||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
||||
if (tooltipAttribute != null)
|
||||
{
|
||||
item.TooltipText += '\n';
|
||||
item.TooltipText += tooltipAttribute.Text;
|
||||
}
|
||||
cm.AddItem(item);
|
||||
cm.AddItem(new TypeSearchPopup.TypeItemView(controlTypes[i]));
|
||||
}
|
||||
|
||||
cm.ItemClicked += controlType => SetType((ScriptType)controlType.Tag);
|
||||
cm.SortChildren();
|
||||
cm.Show(button.Parent, button.BottomLeft);
|
||||
}
|
||||
|
||||
private void SetType(ref ScriptType controlType, UIControl uiControl)
|
||||
{
|
||||
string previousName = uiControl.Control?.GetType().Name ?? nameof(UIControl);
|
||||
uiControl.Control = (Control)controlType.CreateInstance();
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
}
|
||||
}
|
||||
|
||||
private void SetType(ScriptType controlType)
|
||||
{
|
||||
var uiControls = ParentEditor.Values;
|
||||
if (Presenter.Undo != null)
|
||||
if (Presenter.Undo?.Enabled ?? false)
|
||||
{
|
||||
using (new UndoMultiBlock(Presenter.Undo, uiControls, "Set Control Type"))
|
||||
{
|
||||
for (int i = 0; i < uiControls.Count; i++)
|
||||
{
|
||||
var uiControl = (UIControl)uiControls[i];
|
||||
string previousName = uiControl.Control?.GetType()?.Name ?? typeof(UIControl).Name;
|
||||
uiControl.Control = (Control)controlType.CreateInstance();
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
}
|
||||
}
|
||||
SetType(ref controlType, (UIControl)uiControls[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < uiControls.Count; i++)
|
||||
{
|
||||
var uiControl = (UIControl)uiControls[i];
|
||||
string previousName = uiControl.Control?.GetType()?.Name ?? typeof(UIControl).Name;
|
||||
uiControl.Control = (Control)controlType.CreateInstance();
|
||||
if (uiControl.Name.StartsWith(previousName))
|
||||
{
|
||||
string newName = controlType.Name + uiControl.Name.Substring(previousName.Length);
|
||||
uiControl.Name = StringUtils.IncrementNameNumber(newName, x => uiControl.Parent.GetChild(x) == null);
|
||||
}
|
||||
}
|
||||
SetType(ref controlType, (UIControl)uiControls[i]);
|
||||
}
|
||||
|
||||
ParentEditor.RebuildLayout();
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Copy old values
|
||||
Array.Copy(array, 0, newValues, 0, sharedCount);
|
||||
|
||||
if (elementType.IsValueType)
|
||||
if (elementType.IsValueType || NotNullItems)
|
||||
{
|
||||
// Fill new entries with the last value
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
|
||||
@@ -77,11 +77,16 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if value of collection can be null.
|
||||
/// </summary>
|
||||
protected bool NotNullItems;
|
||||
|
||||
private IntegerValueElement _size;
|
||||
private Color _background;
|
||||
private int _elementsCount;
|
||||
private bool _readOnly;
|
||||
private bool _canReorderItems;
|
||||
private bool _notNullItems;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the collection.
|
||||
@@ -103,15 +108,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_readOnly = false;
|
||||
_canReorderItems = true;
|
||||
_notNullItems = false;
|
||||
|
||||
// No support for different collections for now
|
||||
if (HasDifferentValues || HasDifferentTypes)
|
||||
return;
|
||||
|
||||
var size = Count;
|
||||
_readOnly = false;
|
||||
_canReorderItems = true;
|
||||
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
|
||||
NotNullItems = false;
|
||||
|
||||
// Try get CollectionAttribute for collection editor meta
|
||||
var attributes = Values.GetAttributes();
|
||||
@@ -120,17 +125,17 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
||||
if (collection != null)
|
||||
{
|
||||
// TODO: handle NotNullItems by filtering child editors SetValue
|
||||
|
||||
_readOnly = collection.ReadOnly;
|
||||
_canReorderItems = collection.CanReorderItems;
|
||||
_notNullItems = collection.NotNullItems;
|
||||
NotNullItems = collection.NotNullItems;
|
||||
if (collection.BackgroundColor.HasValue)
|
||||
_background = collection.BackgroundColor.Value;
|
||||
overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type;
|
||||
spacing = collection.Spacing;
|
||||
}
|
||||
|
||||
// Size
|
||||
if (_readOnly)
|
||||
if (_readOnly || (NotNullItems && size == 0))
|
||||
{
|
||||
layout.Label("Size", size.ToString());
|
||||
}
|
||||
@@ -146,6 +151,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Elements
|
||||
if (size > 0)
|
||||
{
|
||||
var panel = layout.VerticalPanel();
|
||||
panel.Panel.BackgroundColor = _background;
|
||||
var elementType = ElementType;
|
||||
if (_canReorderItems)
|
||||
{
|
||||
@@ -153,7 +160,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (i != 0 && spacing > 0f)
|
||||
{
|
||||
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
{
|
||||
if (propertiesListElement.Labels.Count > 0)
|
||||
{
|
||||
@@ -166,12 +173,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Space(spacing);
|
||||
panel.Space(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||
layout.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||
panel.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -180,14 +187,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
if (i != 0 && spacing > 0f)
|
||||
{
|
||||
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
propertiesListElement.Space(spacing);
|
||||
else
|
||||
layout.Space(spacing);
|
||||
panel.Space(spacing);
|
||||
}
|
||||
|
||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||
layout.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||
panel.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +209,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Text = "+",
|
||||
TooltipText = "Add new item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = !NotNullItems || size > 0,
|
||||
};
|
||||
addButton.Clicked += () =>
|
||||
{
|
||||
@@ -217,7 +225,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
TooltipText = "Remove last item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = size > 0
|
||||
Enabled = size > 0,
|
||||
};
|
||||
removeButton.Clicked += () =>
|
||||
{
|
||||
@@ -229,6 +237,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the parent layout if its collection.
|
||||
/// </summary>
|
||||
public void RebuildParentCollection()
|
||||
{
|
||||
if (ParentEditor is DictionaryEditor dictionaryEditor)
|
||||
{
|
||||
dictionaryEditor.RebuildParentCollection();
|
||||
dictionaryEditor.RebuildLayout();
|
||||
return;
|
||||
}
|
||||
if (ParentEditor is CollectionEditor collectionEditor)
|
||||
{
|
||||
collectionEditor.RebuildParentCollection();
|
||||
collectionEditor.RebuildLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSizeChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
@@ -312,7 +338,27 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (Count != _elementsCount)
|
||||
{
|
||||
RebuildLayout();
|
||||
RebuildParentCollection();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool OnDirty(CustomEditor editor, object value, object token = null)
|
||||
{
|
||||
if (NotNullItems)
|
||||
{
|
||||
if (value == null && editor.ParentEditor == this)
|
||||
return false;
|
||||
if (editor == this && value is IList list)
|
||||
{
|
||||
for (int i = 0; i < list.Count; i++)
|
||||
{
|
||||
if (list[i] == null)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.OnDirty(editor, value, token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,10 +135,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
|
||||
private IntegerValueElement _size;
|
||||
private Color _background;
|
||||
private int _elementsCount;
|
||||
private bool _readOnly;
|
||||
private bool _notNullItems;
|
||||
private bool _canEditKeys;
|
||||
private bool _keyEdited;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this editor[can edit the specified dictionary type.
|
||||
@@ -164,9 +166,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
_readOnly = false;
|
||||
_notNullItems = false;
|
||||
|
||||
// No support for different collections for now
|
||||
if (HasDifferentValues || HasDifferentTypes)
|
||||
return;
|
||||
@@ -177,23 +176,23 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var keyType = argTypes[0];
|
||||
var valueType = argTypes[1];
|
||||
_canEditKeys = keyType == typeof(string) || keyType.IsPrimitive || keyType.IsEnum;
|
||||
_background = FlaxEngine.GUI.Style.Current.CollectionBackgroundColor;
|
||||
_readOnly = false;
|
||||
_notNullItems = false;
|
||||
|
||||
// Try get CollectionAttribute for collection editor meta
|
||||
var attributes = Values.GetAttributes();
|
||||
Type overrideEditorType = null;
|
||||
float spacing = 0.0f;
|
||||
if (attributes != null)
|
||||
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
||||
if (collection != null)
|
||||
{
|
||||
var collection = (CollectionAttribute)attributes.FirstOrDefault(x => x is CollectionAttribute);
|
||||
if (collection != null)
|
||||
{
|
||||
// TODO: handle ReadOnly and NotNullItems by filtering child editors SetValue
|
||||
|
||||
_readOnly = collection.ReadOnly;
|
||||
_notNullItems = collection.NotNullItems;
|
||||
overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type;
|
||||
spacing = collection.Spacing;
|
||||
}
|
||||
_readOnly = collection.ReadOnly;
|
||||
_notNullItems = collection.NotNullItems;
|
||||
if (collection.BackgroundColor.HasValue)
|
||||
_background = collection.BackgroundColor.Value;
|
||||
overrideEditorType = TypeUtils.GetType(collection.OverrideEditorTypeName).Type;
|
||||
spacing = collection.Spacing;
|
||||
}
|
||||
|
||||
// Size
|
||||
@@ -205,7 +204,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
_size = layout.IntegerValue("Size");
|
||||
_size.IntValue.MinValue = 0;
|
||||
_size.IntValue.MaxValue = ushort.MaxValue;
|
||||
_size.IntValue.MaxValue = _notNullItems ? size : ushort.MaxValue;
|
||||
_size.IntValue.Value = size;
|
||||
_size.IntValue.ValueChanged += OnSizeChanged;
|
||||
}
|
||||
@@ -213,13 +212,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
// Elements
|
||||
if (size > 0)
|
||||
{
|
||||
var panel = layout.VerticalPanel();
|
||||
panel.Panel.BackgroundColor = _background;
|
||||
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
|
||||
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
if (i != 0 && spacing > 0f)
|
||||
{
|
||||
if (layout.Children.Count > 0 && layout.Children[layout.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
if (panel.Children.Count > 0 && panel.Children[panel.Children.Count - 1] is PropertiesListElement propertiesListElement)
|
||||
{
|
||||
if (propertiesListElement.Labels.Count > 0)
|
||||
{
|
||||
@@ -232,13 +233,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
layout.Space(spacing);
|
||||
panel.Space(spacing);
|
||||
}
|
||||
}
|
||||
|
||||
var key = keys.ElementAt(i);
|
||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||
layout.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(new ScriptType(valueType), key, Values), overrideEditor);
|
||||
panel.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(new ScriptType(valueType), key, Values), overrideEditor);
|
||||
}
|
||||
}
|
||||
_elementsCount = size;
|
||||
@@ -252,7 +253,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Text = "+",
|
||||
TooltipText = "Add new item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = !_notNullItems,
|
||||
};
|
||||
addButton.Clicked += () =>
|
||||
{
|
||||
@@ -267,7 +269,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
TooltipText = "Remove last item",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
Parent = area.ContainerControl,
|
||||
Enabled = size > 0
|
||||
Enabled = size > 0,
|
||||
};
|
||||
removeButton.Clicked += () =>
|
||||
{
|
||||
@@ -279,6 +281,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rebuilds the parent layout if its collection.
|
||||
/// </summary>
|
||||
public void RebuildParentCollection()
|
||||
{
|
||||
if (ParentEditor is DictionaryEditor dictionaryEditor)
|
||||
{
|
||||
dictionaryEditor.RebuildParentCollection();
|
||||
dictionaryEditor.RebuildLayout();
|
||||
return;
|
||||
}
|
||||
if (ParentEditor is CollectionEditor collectionEditor)
|
||||
{
|
||||
collectionEditor.RebuildParentCollection();
|
||||
collectionEditor.RebuildLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSizeChanged()
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
@@ -332,6 +352,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
newValues[e] = dictionary[e];
|
||||
}
|
||||
SetValue(newValues);
|
||||
_keyEdited = true; // TODO: use custom UndoAction to rebuild UI after key modification
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -444,6 +465,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
if (_keyEdited)
|
||||
{
|
||||
_keyEdited = false;
|
||||
RebuildLayout();
|
||||
RebuildParentCollection();
|
||||
}
|
||||
|
||||
base.Refresh();
|
||||
|
||||
// No support for different collections for now
|
||||
@@ -454,6 +482,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (Count != _elementsCount)
|
||||
{
|
||||
RebuildLayout();
|
||||
RebuildParentCollection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
private IFloatValueEditor _element;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the element.
|
||||
/// </summary>
|
||||
public IFloatValueEditor Element => _element;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override DisplayStyle Style => DisplayStyle.Inline;
|
||||
|
||||
@@ -84,7 +89,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
else if (value is double asDouble)
|
||||
_element.Value = (float)asDouble;
|
||||
else
|
||||
throw new Exception("Invalid value.");
|
||||
throw new Exception(string.Format("Invalid value type {0}.", value?.GetType().ToString() ?? "<null>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
new OptionType("Material", typeof(MaterialBrush)),
|
||||
new OptionType("Solid Color", typeof(SolidColorBrush)),
|
||||
new OptionType("Linear Gradient", typeof(LinearGradientBrush)),
|
||||
new OptionType("Texture 9-Slicing", typeof(Texture9SlicingBrush)),
|
||||
new OptionType("Sprite 9-Slicing", typeof(Sprite9SlicingBrush)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.CustomEditors.Elements;
|
||||
using FlaxEngine;
|
||||
@@ -77,7 +78,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
else
|
||||
{
|
||||
_element.Value = (int)Values[0];
|
||||
var value = Values[0];
|
||||
if (value is int asInt)
|
||||
_element.Value = asInt;
|
||||
else if (value is float asFloat)
|
||||
_element.Value = (int)asFloat;
|
||||
else
|
||||
throw new Exception(string.Format("Invalid value type {0}.", value?.GetType().ToString() ?? "<null>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var list = (IList)listType.CreateInstance();
|
||||
var defaultValue = Scripting.TypeUtils.GetDefaultValue(ElementType);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
list.Add(defaultValue);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -48,7 +46,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
for (int i = 0; i < sharedCount; i++)
|
||||
newValues.Add(list[i]);
|
||||
|
||||
if (elementType.IsValueType)
|
||||
if (elementType.IsValueType || NotNullItems)
|
||||
{
|
||||
// Fill new entries with the last value
|
||||
for (int i = oldSize; i < newSize; i++)
|
||||
@@ -86,9 +84,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var cloned = (IList)listType.CreateInstance();
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
cloned.Add(list[i]);
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
35
Source/Editor/CustomEditors/Editors/MarginEditor.cs
Normal file
35
Source/Editor/CustomEditors/Editors/MarginEditor.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Linq;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// Default implementation of the inspector used to edit Version value type properties.
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(Margin)), DefaultEditor]
|
||||
public class MarginEditor : GenericEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
var attributes = Values.GetAttributes();
|
||||
if (attributes != null)
|
||||
{
|
||||
var limit = (LimitAttribute)attributes.FirstOrDefault(x => x is LimitAttribute);
|
||||
if (limit != null)
|
||||
{
|
||||
for (var i = 0; i < ChildrenEditors.Count; i++)
|
||||
{
|
||||
if (ChildrenEditors[i] is FloatEditor floatEditor)
|
||||
floatEditor.Element.SetLimits(limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,8 +38,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var model = staticModel.Model;
|
||||
if (model && model.IsLoaded)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + model.MaterialSlots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
var slots = model.MaterialSlots;
|
||||
if (slots != null && slots.Length > entryIndex)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ParentEditor.ParentEditor.Values[0] is AnimatedModel animatedModel)
|
||||
@@ -47,8 +51,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var model = animatedModel.SkinnedModel;
|
||||
if (model && model.IsLoaded)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + model.MaterialSlots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
var slots = model.MaterialSlots;
|
||||
if (slots != null && slots.Length > entryIndex)
|
||||
{
|
||||
_group.Panel.HeaderText = "Entry " + slots[entryIndex].Name;
|
||||
_updateName = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Elements
|
||||
{
|
||||
/// <summary>
|
||||
@@ -16,5 +18,11 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// Gets a value indicating whether user is using a slider.
|
||||
/// </summary>
|
||||
bool IsSliding { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the editor limits from member <see cref="LimitAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="limit">The limit.</param>
|
||||
void SetLimits(LimitAttribute limit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,5 +76,14 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
|
||||
/// <inheritdoc cref="IFloatValueEditor.IsSliding" />
|
||||
public bool IsSliding => Slider.IsSliding;
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetLimits(LimitAttribute limit)
|
||||
{
|
||||
if (limit != null)
|
||||
{
|
||||
Slider.SetLimits(limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace FlaxEditor.CustomEditors
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds new horizontal panel element.
|
||||
/// Adds new vertical panel element.
|
||||
/// </summary>
|
||||
/// <returns>The created element.</returns>
|
||||
public VerticalPanelElement VerticalPanel()
|
||||
|
||||
@@ -112,9 +112,9 @@ namespace FlaxEditor.CustomEditors
|
||||
EndUndoRecord();
|
||||
_setValueToken = token;
|
||||
|
||||
// Mark as modified and don't pass event further
|
||||
// Mark as modified and don't pass event further to the higher editors (don't call parent)
|
||||
_isDirty = true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -255,8 +255,15 @@ namespace FlaxEditor.CustomEditors
|
||||
if (instanceValues._referenceValue == null && !instanceValues.Type.IsValueType)
|
||||
return;
|
||||
|
||||
_referenceValue = Info.GetValue(instanceValues._referenceValue);
|
||||
_hasReferenceValue = true;
|
||||
try
|
||||
{
|
||||
_referenceValue = Info.GetValue(instanceValues._referenceValue);
|
||||
_hasReferenceValue = true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Ignore error if reference value has different type or is invalid for this member
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -518,7 +518,7 @@ bool Editor::Init()
|
||||
exit(failed ? 1 : 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// If during last lightmaps baking engine crashed we could try to restore the progress
|
||||
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
|
||||
|
||||
@@ -534,6 +534,12 @@ bool Editor::Init()
|
||||
// Initialize managed editor
|
||||
Managed->Init();
|
||||
|
||||
// Start play if requested by cmd line
|
||||
if (CommandLine::Options.Play.HasValue())
|
||||
{
|
||||
Managed->RequestStartPlayOnEditMode();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace FlaxEditor
|
||||
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode;
|
||||
private string _projectToOpen;
|
||||
private float _lastAutoSaveTimer;
|
||||
private Guid _startupSceneCmdLine;
|
||||
|
||||
private const string ProjectDataLastScene = "LastScene";
|
||||
private const string ProjectDataLastSceneSpawn = "LastSceneSpawn";
|
||||
@@ -271,10 +272,11 @@ namespace FlaxEditor
|
||||
module.OnEndInit();
|
||||
}
|
||||
|
||||
internal void Init(bool isHeadless, bool skipCompile)
|
||||
internal void Init(bool isHeadless, bool skipCompile, Guid startupScene)
|
||||
{
|
||||
EnsureState<LoadingState>();
|
||||
_isHeadlessMode = isHeadless;
|
||||
_startupSceneCmdLine = startupScene;
|
||||
Log("Editor init");
|
||||
if (isHeadless)
|
||||
Log("Running in headless mode");
|
||||
@@ -332,6 +334,17 @@ namespace FlaxEditor
|
||||
}
|
||||
|
||||
// Load scene
|
||||
|
||||
// scene cmd line argument
|
||||
var scene = ContentDatabase.Find(_startupSceneCmdLine);
|
||||
if (scene is SceneItem)
|
||||
{
|
||||
Editor.Log("Loading scene specified in command line");
|
||||
Scene.OpenScene(_startupSceneCmdLine);
|
||||
return;
|
||||
}
|
||||
|
||||
// if no scene cmd line argument is provided
|
||||
var startupSceneMode = Options.Options.General.StartupSceneMode;
|
||||
if (startupSceneMode == GeneralOptions.StartupSceneModes.LastOpened && !ProjectCache.HasCustomData(ProjectDataLastScene))
|
||||
{
|
||||
@@ -1293,20 +1306,17 @@ namespace FlaxEditor
|
||||
VisualScriptingDebugFlow?.Invoke(debugFlow);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct AnimGraphDebugFlowInfo
|
||||
private static void RequestStartPlayOnEditMode()
|
||||
{
|
||||
public Asset Asset;
|
||||
public FlaxEngine.Object Object;
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
if (Instance.StateMachine.IsEditMode)
|
||||
Instance.Simulation.RequestStartPlay();
|
||||
if (Instance.StateMachine.IsPlayMode)
|
||||
Instance.StateMachine.StateChanged -= RequestStartPlayOnEditMode;
|
||||
}
|
||||
|
||||
internal static event Action<AnimGraphDebugFlowInfo> AnimGraphDebugFlow;
|
||||
|
||||
internal static void Internal_OnAnimGraphDebugFlow(ref AnimGraphDebugFlowInfo debugFlow)
|
||||
internal static void Internal_RequestStartPlayOnEditMode()
|
||||
{
|
||||
AnimGraphDebugFlow?.Invoke(debugFlow);
|
||||
Instance.StateMachine.StateChanged += RequestStartPlayOnEditMode;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.InternalCall)]
|
||||
|
||||
@@ -46,6 +46,12 @@ namespace FlaxEditor
|
||||
public SpriteHandle Down32;
|
||||
public SpriteHandle FolderClosed32;
|
||||
public SpriteHandle FolderOpen32;
|
||||
public SpriteHandle Folder32;
|
||||
public SpriteHandle CameraFill32;
|
||||
public SpriteHandle Search32;
|
||||
public SpriteHandle Info32;
|
||||
public SpriteHandle Warning32;
|
||||
public SpriteHandle Error32;
|
||||
|
||||
// Visject
|
||||
public SpriteHandle VisjectBoxOpen32;
|
||||
@@ -128,6 +134,10 @@ namespace FlaxEditor
|
||||
public SpriteHandle AndroidIcon128;
|
||||
public SpriteHandle PS4Icon128;
|
||||
public SpriteHandle FlaxLogo128;
|
||||
public SpriteHandle SwitchIcon128;
|
||||
public SpriteHandle SwitchSettings128;
|
||||
public SpriteHandle LocalizationSettings128;
|
||||
public SpriteHandle Json128;
|
||||
|
||||
internal void LoadIcons()
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace FlaxEditor.GUI
|
||||
/// The label that contains events for mouse interaction.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEngine.GUI.Label" />
|
||||
[HideInEditor]
|
||||
public class ClickableLabel : Label
|
||||
{
|
||||
private bool _leftClick;
|
||||
|
||||
@@ -84,7 +84,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <summary>
|
||||
/// The default tabs header buttons size.
|
||||
/// </summary>
|
||||
public const float DefaultButtonsSize = 12;
|
||||
public const float DefaultButtonsSize = 15;
|
||||
|
||||
/// <summary>
|
||||
/// The default tabs header buttons margin.
|
||||
|
||||
@@ -410,6 +410,17 @@ namespace FlaxEditor.GUI.Input
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the limits from the attribute.
|
||||
/// </summary>
|
||||
/// <param name="limits">The limits.</param>
|
||||
public void SetLimits(LimitAttribute limits)
|
||||
{
|
||||
_min = limits.Min;
|
||||
_max = Mathf.Max(_min, limits.Max);
|
||||
Value = Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the text of the textbox.
|
||||
/// </summary>
|
||||
|
||||
@@ -32,9 +32,14 @@ namespace FlaxEditor.GUI
|
||||
protected List<Rectangle> _highlights;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name.
|
||||
/// The item name.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// The item category name (optional).
|
||||
/// </summary>
|
||||
public string Category;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when items gets clicked by the user.
|
||||
@@ -49,18 +54,6 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Item"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The item name.</param>
|
||||
/// <param name="tag">The item tag object.</param>
|
||||
public Item(string name, object tag = null)
|
||||
: base(0, 0, 120, 12)
|
||||
{
|
||||
Name = name;
|
||||
Tag = tag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the filter.
|
||||
/// </summary>
|
||||
@@ -181,6 +174,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
|
||||
private readonly TextBox _searchBox;
|
||||
private List<DropPanel> _categoryPanels;
|
||||
private bool _waitingForInput;
|
||||
|
||||
/// <summary>
|
||||
@@ -242,6 +236,23 @@ namespace FlaxEditor.GUI
|
||||
if (items[i] is Item item)
|
||||
item.UpdateFilter(_searchBox.Text);
|
||||
}
|
||||
if (_categoryPanels != null)
|
||||
{
|
||||
for (int i = 0; i < _categoryPanels.Count; i++)
|
||||
{
|
||||
var category = _categoryPanels[i];
|
||||
bool anyVisible = false;
|
||||
for (int j = 0; j < category.Children.Count; j++)
|
||||
{
|
||||
if (category.Children[j] is Item item2)
|
||||
{
|
||||
item2.UpdateFilter(_searchBox.Text);
|
||||
anyVisible |= item2.Visible;
|
||||
}
|
||||
}
|
||||
category.Visible = anyVisible;
|
||||
}
|
||||
}
|
||||
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout(true);
|
||||
@@ -254,8 +265,33 @@ namespace FlaxEditor.GUI
|
||||
/// <param name="item">The item.</param>
|
||||
public void AddItem(Item item)
|
||||
{
|
||||
item.Parent = ItemsPanel;
|
||||
item.Clicked += OnClickItem;
|
||||
ContainerControl parent = ItemsPanel;
|
||||
if (!string.IsNullOrEmpty(item.Category))
|
||||
{
|
||||
if (_categoryPanels == null)
|
||||
_categoryPanels = new List<DropPanel>();
|
||||
for (int i = 0; i < _categoryPanels.Count; i++)
|
||||
{
|
||||
if (string.Equals(_categoryPanels[i].HeaderText, item.Category, StringComparison.Ordinal))
|
||||
{
|
||||
parent = _categoryPanels[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent == ItemsPanel)
|
||||
{
|
||||
var categoryPanel = new DropPanel
|
||||
{
|
||||
HeaderText = item.Category,
|
||||
Parent = parent,
|
||||
};
|
||||
categoryPanel.Open(false);
|
||||
_categoryPanels.Add(categoryPanel);
|
||||
parent = categoryPanel;
|
||||
}
|
||||
}
|
||||
item.Parent = parent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -281,6 +317,19 @@ namespace FlaxEditor.GUI
|
||||
if (items[i] is Item item)
|
||||
item.UpdateFilter(null);
|
||||
}
|
||||
if (_categoryPanels != null)
|
||||
{
|
||||
for (int i = 0; i < _categoryPanels.Count; i++)
|
||||
{
|
||||
var category = _categoryPanels[i];
|
||||
for (int j = 0; j < category.Children.Count; j++)
|
||||
{
|
||||
if (category.Children[j] is Item item2)
|
||||
item2.UpdateFilter(null);
|
||||
}
|
||||
category.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
_searchBox.Clear();
|
||||
UnlockChildrenRecursive();
|
||||
|
||||
@@ -19,6 +19,7 @@ namespace FlaxEditor.GUI
|
||||
private Button _closeButton;
|
||||
private Button _minimizeButton;
|
||||
private Button _maximizeButton;
|
||||
private LocalizedString _charChromeRestore, _charChromeMaximize;
|
||||
private Window _window;
|
||||
#endif
|
||||
private MainMenuButton _selected;
|
||||
@@ -151,14 +152,12 @@ namespace FlaxEditor.GUI
|
||||
_maximizeButton.Clicked += () =>
|
||||
{
|
||||
if (_window.IsMaximized)
|
||||
{
|
||||
_window.Restore();
|
||||
}
|
||||
else
|
||||
{
|
||||
_window.Maximize();
|
||||
}
|
||||
};
|
||||
_charChromeRestore = ((char)EditorAssets.SegMDL2Icons.ChromeRestore).ToString();
|
||||
_charChromeMaximize = ((char)EditorAssets.SegMDL2Icons.ChromeMaximize).ToString();
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -175,7 +174,7 @@ namespace FlaxEditor.GUI
|
||||
|
||||
if (_maximizeButton != null)
|
||||
{
|
||||
_maximizeButton.Text = ((char)(_window.IsMaximized ? EditorAssets.SegMDL2Icons.ChromeRestore : EditorAssets.SegMDL2Icons.ChromeMaximize)).ToString();
|
||||
_maximizeButton.Text = _window.IsMaximized ? _charChromeRestore : _charChromeMaximize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -89,11 +89,10 @@ namespace FlaxEditor.GUI
|
||||
new PlatformData(PlatformType.PS4, icons.PS4Icon128, "PlayStation 4"),
|
||||
new PlatformData(PlatformType.XboxScarlett, icons.XBoxScarletIcon128, "Xbox Scarlett"),
|
||||
new PlatformData(PlatformType.Android, icons.AndroidIcon128, "Android"),
|
||||
new PlatformData(PlatformType.Switch, icons.ColorWheel128, "Switch"),
|
||||
|
||||
new PlatformData(PlatformType.Switch, icons.SwitchIcon128, "Switch"),
|
||||
};
|
||||
|
||||
const float IconSize = 48.0f;
|
||||
const float IconSize = 64.0f;
|
||||
TileSize = new Vector2(IconSize);
|
||||
AutoResize = true;
|
||||
Offsets = new Margin(0, 0, 0, IconSize);
|
||||
|
||||
@@ -27,6 +27,15 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public ScriptType Type => _type;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeItemView"/> class.
|
||||
/// </summary>
|
||||
/// <param name="type">The type.</param>
|
||||
public TypeItemView(ScriptType type)
|
||||
: this(type, type.GetAttributes(false))
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TypeItemView"/> class.
|
||||
/// </summary>
|
||||
@@ -38,12 +47,18 @@ namespace FlaxEditor.GUI
|
||||
|
||||
Name = type.Name;
|
||||
TooltipText = type.TypeName;
|
||||
Tag = type;
|
||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
||||
if (tooltipAttribute != null)
|
||||
{
|
||||
TooltipText += '\n';
|
||||
TooltipText += tooltipAttribute.Text;
|
||||
}
|
||||
var categoryAttribute = (CategoryAttribute)attributes.FirstOrDefault(x => x is CategoryAttribute);
|
||||
if (categoryAttribute != null)
|
||||
{
|
||||
Category = categoryAttribute.Name;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -70,7 +70,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
: base(ref options)
|
||||
{
|
||||
// Select Actor button
|
||||
const float buttonSize = 14;
|
||||
const float buttonSize = 18;
|
||||
var icons = Editor.Instance.Icons;
|
||||
_selectActor = new Image
|
||||
{
|
||||
@@ -80,7 +80,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
IsScrollable = false,
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Search12),
|
||||
Brush = new SpriteBrush(icons.Search32),
|
||||
Offsets = new Margin(-buttonSize - 2 + _addButton.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Parent = this,
|
||||
};
|
||||
|
||||
@@ -312,7 +312,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
Curve.UnlockChildrenRecursive();
|
||||
|
||||
// Navigation buttons
|
||||
const float buttonSize = 14;
|
||||
const float keySize = 18;
|
||||
const float addSize = 20;
|
||||
var icons = Editor.Instance.Icons;
|
||||
var rightKey = new Image
|
||||
{
|
||||
@@ -323,7 +324,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Right32),
|
||||
Offsets = new Margin(-buttonSize - 2 + _muteCheckbox.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Offsets = new Margin(-keySize - 2 + _muteCheckbox.Offsets.Left, keySize, keySize * -0.5f, keySize),
|
||||
Parent = this,
|
||||
};
|
||||
rightKey.Clicked += OnRightKeyClicked;
|
||||
@@ -336,7 +337,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(3),
|
||||
Brush = new SpriteBrush(icons.Add32),
|
||||
Offsets = new Margin(-buttonSize - 2 + rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Offsets = new Margin(-addSize - 2 + rightKey.Offsets.Left, addSize, addSize * -0.5f, addSize),
|
||||
Parent = this,
|
||||
};
|
||||
addKey.Clicked += OnAddKeyClicked;
|
||||
@@ -349,7 +350,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Left32),
|
||||
Offsets = new Margin(-buttonSize - 2 + addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Offsets = new Margin(-keySize - 2 + addKey.Offsets.Left, keySize, keySize * -0.5f, keySize),
|
||||
Parent = this,
|
||||
};
|
||||
leftKey.Clicked += OnLeftKeyClicked;
|
||||
|
||||
@@ -471,7 +471,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
_atlases = new List<Atlas>(4);
|
||||
if (_output == null)
|
||||
{
|
||||
_output = GPUDevice.Instance.CreateTexture();
|
||||
_output = GPUDevice.Instance.CreateTexture("CameraCutMedia.Output");
|
||||
var desc = GPUTextureDescription.New2D(Width, Height, PixelFormat.R8G8B8A8_UNorm);
|
||||
_output.Init(ref desc);
|
||||
}
|
||||
@@ -682,10 +682,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
public CameraCutTrack(ref TrackCreateOptions options)
|
||||
: base(ref options)
|
||||
{
|
||||
Height = CameraCutThumbnailRenderer.Height + 4 + 4;
|
||||
Height = CameraCutThumbnailRenderer.Height + 8;
|
||||
|
||||
// Pilot Camera button
|
||||
const float buttonSize = 14;
|
||||
const float buttonSize = 18;
|
||||
var icons = Editor.Instance.Icons;
|
||||
_pilotCamera = new Image
|
||||
{
|
||||
@@ -695,7 +695,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
IsScrollable = false,
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Camera64),
|
||||
Brush = new SpriteBrush(icons.CameraFill32),
|
||||
Offsets = new Margin(-buttonSize - 2 + _selectActor.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Parent = this,
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
{
|
||||
TypeId = 1,
|
||||
Name = "Folder",
|
||||
Icon = Editor.Instance.Icons.Folder64,
|
||||
Icon = Editor.Instance.Icons.Folder32,
|
||||
Create = options => new FolderTrack(ref options),
|
||||
Load = LoadTrack,
|
||||
Save = SaveTrack,
|
||||
|
||||
@@ -118,7 +118,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
if (useNavigationButtons)
|
||||
{
|
||||
// Navigation buttons
|
||||
const float buttonSize = 14;
|
||||
const float keySize = 18;
|
||||
const float addSize = 20;
|
||||
var icons = Editor.Instance.Icons;
|
||||
_rightKey = new Image
|
||||
{
|
||||
@@ -128,8 +129,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
IsScrollable = false,
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Right64),
|
||||
Offsets = new Margin(-buttonSize - 2 + uiLeft, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Brush = new SpriteBrush(icons.Right32),
|
||||
Offsets = new Margin(-keySize - 2 + uiLeft, keySize, keySize * -0.5f, keySize),
|
||||
Parent = this,
|
||||
};
|
||||
_addKey = new Image
|
||||
@@ -138,10 +139,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.MiddleRight,
|
||||
IsScrollable = false,
|
||||
Color = Style.Current.Foreground,
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(3),
|
||||
Brush = new SpriteBrush(icons.Add64),
|
||||
Offsets = new Margin(-buttonSize - 2 + _rightKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Brush = new SpriteBrush(icons.Add32),
|
||||
Offsets = new Margin(-addSize - 2 + _rightKey.Offsets.Left, addSize, addSize * -0.5f, addSize),
|
||||
Parent = this,
|
||||
};
|
||||
_leftKey = new Image
|
||||
@@ -150,10 +151,10 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
AutoFocus = true,
|
||||
AnchorPreset = AnchorPresets.MiddleRight,
|
||||
IsScrollable = false,
|
||||
Color = Style.Current.Foreground,
|
||||
Color = Style.Current.ForegroundGrey,
|
||||
Margin = new Margin(1),
|
||||
Brush = new SpriteBrush(icons.Left64),
|
||||
Offsets = new Margin(-buttonSize - 2 + _addKey.Offsets.Left, buttonSize, buttonSize * -0.5f, buttonSize),
|
||||
Brush = new SpriteBrush(icons.Left32),
|
||||
Offsets = new Margin(-keySize - 2 + _addKey.Offsets.Left, keySize, keySize * -0.5f, keySize),
|
||||
Parent = this,
|
||||
};
|
||||
uiLeft = _leftKey.Offsets.Left;
|
||||
|
||||
@@ -723,12 +723,6 @@ namespace FlaxEditor.GUI.Tree
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||
{
|
||||
// Check if mouse hits bar
|
||||
if (button == MouseButton.Right && TestHeaderHit(ref location))
|
||||
{
|
||||
ParentTree.OnRightClickInternal(this, ref location);
|
||||
}
|
||||
|
||||
// Clear flag for left button
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
@@ -773,11 +767,23 @@ namespace FlaxEditor.GUI.Tree
|
||||
Expand();
|
||||
}
|
||||
|
||||
// Check if mouse hits bar
|
||||
if (button == MouseButton.Right && TestHeaderHit(ref location))
|
||||
{
|
||||
ParentTree.OnRightClickInternal(this, ref location);
|
||||
}
|
||||
|
||||
// Handled
|
||||
Focus();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if mouse hits bar
|
||||
if (button == MouseButton.Right && TestHeaderHit(ref location))
|
||||
{
|
||||
ParentTree.OnRightClickInternal(this, ref location);
|
||||
}
|
||||
|
||||
// Base
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ namespace FlaxEditor.Gizmo
|
||||
/// <summary>
|
||||
/// Interface for editor viewports that can contain and use <see cref="EditorPrimitives"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Gizmo.IGizmoOwner" />
|
||||
[HideInEditor]
|
||||
public interface IEditorPrimitivesOwner : IGizmoOwner
|
||||
public interface IEditorPrimitivesOwner
|
||||
{
|
||||
/// <summary>
|
||||
/// Draws the custom editor primitives.
|
||||
@@ -68,11 +67,14 @@ namespace FlaxEditor.Gizmo
|
||||
var renderList = RenderList.GetFromPool();
|
||||
var prevList = renderContext.List;
|
||||
renderContext.List = renderList;
|
||||
for (int i = 0; i < Viewport.Gizmos.Count; i++)
|
||||
try
|
||||
{
|
||||
Viewport.Gizmos[i].Draw(ref renderContext);
|
||||
Viewport.DrawEditorPrimitives(context, ref renderContext, target, targetDepth);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Editor.LogWarning(ex);
|
||||
}
|
||||
Viewport.DrawEditorPrimitives(context, ref renderContext, target, targetDepth);
|
||||
|
||||
// Sort draw calls
|
||||
renderList.SortDrawCalls(ref renderContext, false, DrawCallsListType.GBuffer);
|
||||
|
||||
@@ -22,6 +22,16 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
public bool IsActive => Owner.Gizmos.Active == this;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this gizmo is using mouse currently (eg. user moving objects).
|
||||
/// </summary>
|
||||
public virtual bool IsControllingMouse => false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the custom world-space bounds for current gizmo mode focus for used (eg. selected object part bounds). Returns <see cref="BoundingSphere.Empty"/> if not used.
|
||||
/// </summary>
|
||||
public virtual BoundingSphere FocusBounds => BoundingSphere.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="GizmoBase"/> class.
|
||||
/// </summary>
|
||||
|
||||
@@ -70,8 +70,6 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (!_modelTranslateAxis || !_modelTranslateAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
break;
|
||||
|
||||
// Cache data
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref _gizmoWorld, out m1);
|
||||
var axisMesh = _modelTranslateAxis.LODs[0].Meshes[0];
|
||||
@@ -113,8 +111,6 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (!_modelCircle || !_modelCircle.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
break;
|
||||
|
||||
// Cache data
|
||||
var circleMesh = _modelCircle.LODs[0].Meshes[0];
|
||||
var boxMesh = _modelBox.LODs[0].Meshes[0];
|
||||
Matrix.Scaling(8.0f, out m3);
|
||||
@@ -147,8 +143,6 @@ namespace FlaxEditor.Gizmo
|
||||
{
|
||||
if (!_modelScaleAxis || !_modelScaleAxis.IsLoaded || !_modelBox || !_modelBox.IsLoaded)
|
||||
break;
|
||||
|
||||
// Cache data
|
||||
Matrix.Scaling(gizmoModelsScale2RealGizmoSize, out m3);
|
||||
Matrix.Multiply(ref m3, ref _gizmoWorld, out m1);
|
||||
var axisMesh = _modelScaleAxis.LODs[0].Meshes[0];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FlaxEngine;
|
||||
|
||||
@@ -65,6 +66,16 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
public Transform LastDelta { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when transforming selection started.
|
||||
/// </summary>
|
||||
public event Action TransformingStarted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when transforming selection ended.
|
||||
/// </summary>
|
||||
public event Action TransformingEnded;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="TransformGizmoBase" /> class.
|
||||
/// </summary>
|
||||
@@ -118,10 +129,10 @@ namespace FlaxEditor.Gizmo
|
||||
return;
|
||||
|
||||
// End action
|
||||
OnEndTransforming();
|
||||
_startTransforms.Clear();
|
||||
_isTransforming = false;
|
||||
_isDuplicating = false;
|
||||
OnEndTransforming();
|
||||
_startTransforms.Clear();
|
||||
}
|
||||
|
||||
private void UpdateGizmoPosition()
|
||||
@@ -202,52 +213,77 @@ namespace FlaxEditor.Gizmo
|
||||
ray.Position = Vector3.Transform(ray.Position, invRotationMatrix);
|
||||
Vector3.TransformNormal(ref ray.Direction, ref invRotationMatrix, out ray.Direction);
|
||||
|
||||
var planeXY = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z);
|
||||
var planeYZ = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X);
|
||||
var planeZX = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y);
|
||||
var dir = Vector3.Normalize(ray.Position - Position);
|
||||
var planeDotXY = Mathf.Abs(Vector3.Dot(planeXY.Normal, dir));
|
||||
var planeDotYZ = Mathf.Abs(Vector3.Dot(planeYZ.Normal, dir));
|
||||
var planeDotZX = Mathf.Abs(Vector3.Dot(planeZX.Normal, dir));
|
||||
|
||||
switch (_activeAxis)
|
||||
{
|
||||
case Axis.XY:
|
||||
case Axis.X:
|
||||
{
|
||||
var plane = new Plane(Vector3.Backward, Vector3.Transform(Position, invRotationMatrix).Z);
|
||||
var plane = planeDotXY > planeDotZX ? planeXY : planeZX;
|
||||
if (ray.Intersects(ref plane, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = _activeAxis == Axis.X
|
||||
? new Vector3(_tDelta.X, 0, 0)
|
||||
: new Vector3(_tDelta.X, _tDelta.Y, 0);
|
||||
delta = new Vector3(_tDelta.X, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Axis.Y:
|
||||
{
|
||||
var plane = planeDotXY > planeDotYZ ? planeXY : planeYZ;
|
||||
if (ray.Intersects(ref plane, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(0, _tDelta.Y, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Axis.Z:
|
||||
case Axis.YZ:
|
||||
case Axis.Y:
|
||||
{
|
||||
var plane = new Plane(Vector3.Left, Vector3.Transform(Position, invRotationMatrix).X);
|
||||
var plane = planeDotZX > planeDotYZ ? planeZX : planeYZ;
|
||||
if (ray.Intersects(ref plane, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
switch (_activeAxis)
|
||||
{
|
||||
case Axis.Y:
|
||||
delta = new Vector3(0, _tDelta.Y, 0);
|
||||
break;
|
||||
case Axis.Z:
|
||||
delta = new Vector3(0, 0, _tDelta.Z);
|
||||
break;
|
||||
default:
|
||||
delta = new Vector3(0, _tDelta.Y, _tDelta.Z);
|
||||
break;
|
||||
}
|
||||
delta = new Vector3(0, 0, _tDelta.Z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Axis.YZ:
|
||||
{
|
||||
if (ray.Intersects(ref planeYZ, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(0, _tDelta.Y, _tDelta.Z);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Axis.XY:
|
||||
{
|
||||
if (ray.Intersects(ref planeXY, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
_tDelta = _intersectPosition - _lastIntersectionPosition;
|
||||
delta = new Vector3(_tDelta.X, _tDelta.Y, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Axis.ZX:
|
||||
{
|
||||
var plane = new Plane(Vector3.Down, Vector3.Transform(Position, invRotationMatrix).Y);
|
||||
if (ray.Intersects(ref plane, out float intersection))
|
||||
if (ray.Intersects(ref planeZX, out float intersection))
|
||||
{
|
||||
_intersectPosition = ray.Position + ray.Direction * intersection;
|
||||
if (_lastIntersectionPosition != Vector3.Zero)
|
||||
@@ -271,12 +307,11 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
if (isScaling)
|
||||
delta *= 0.01f;
|
||||
|
||||
if (Owner.IsAltKeyDown)
|
||||
delta *= 0.5f;
|
||||
|
||||
if ((isScaling ? ScaleSnapEnabled : TranslationSnapEnable) || Owner.UseSnapping)
|
||||
{
|
||||
float snapValue = isScaling ? ScaleSnapValue : TranslationSnapValue;
|
||||
@@ -347,6 +382,9 @@ namespace FlaxEditor.Gizmo
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => _isTransforming;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
{
|
||||
@@ -512,6 +550,7 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
protected virtual void OnStartTransforming()
|
||||
{
|
||||
TransformingStarted?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -529,6 +568,7 @@ namespace FlaxEditor.Gizmo
|
||||
/// </summary>
|
||||
protected virtual void OnEndTransforming()
|
||||
{
|
||||
TransformingEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -66,6 +66,7 @@ struct InternalTextureOptions
|
||||
float PreserveAlphaCoverageReference;
|
||||
float Scale;
|
||||
int32 MaxSize;
|
||||
int32 TextureGroup;
|
||||
int32 SizeX;
|
||||
int32 SizeY;
|
||||
MonoArray* SpriteAreas;
|
||||
@@ -86,6 +87,7 @@ struct InternalTextureOptions
|
||||
to->PreserveAlphaCoverage = from->PreserveAlphaCoverage;
|
||||
to->PreserveAlphaCoverageReference = from->PreserveAlphaCoverageReference;
|
||||
to->MaxSize = from->MaxSize;
|
||||
to->TextureGroup = from->TextureGroup;
|
||||
to->SizeX = from->SizeX;
|
||||
to->SizeY = from->SizeY;
|
||||
to->Sprites.Clear();
|
||||
@@ -118,6 +120,7 @@ struct InternalTextureOptions
|
||||
to->PreserveAlphaCoverageReference = from->PreserveAlphaCoverageReference;
|
||||
to->Scale = from->Scale;
|
||||
to->MaxSize = from->MaxSize;
|
||||
to->TextureGroup = from->TextureGroup;
|
||||
to->SizeX = from->SizeX;
|
||||
to->SizeY = from->SizeY;
|
||||
if (from->Sprites.HasItems())
|
||||
|
||||
@@ -34,7 +34,7 @@ MMethod* Internal_GetGameWinPtr = nullptr;
|
||||
MMethod* Internal_GetGameWindowSize = nullptr;
|
||||
MMethod* Internal_OnAppExit = nullptr;
|
||||
MMethod* Internal_OnVisualScriptingDebugFlow = nullptr;
|
||||
MMethod* Internal_OnAnimGraphDebugFlow = nullptr;
|
||||
MMethod* Internal_RequestStartPlayOnEditMode = nullptr;
|
||||
|
||||
void OnLightmapsBake(ShadowsOfMordor::BuildProgressStep step, float stepProgress, float totalProgress, bool isProgressEvent)
|
||||
{
|
||||
@@ -137,38 +137,6 @@ void OnVisualScriptingDebugFlow()
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimGraphDebugFlowInfo
|
||||
{
|
||||
MonoObject* Asset;
|
||||
MonoObject* Object;
|
||||
uint32 NodeId;
|
||||
int32 BoxId;
|
||||
};
|
||||
|
||||
void OnAnimGraphDebugFlow(Asset* asset, ScriptingObject* object, uint32 nodeId, uint32 boxId)
|
||||
{
|
||||
if (Internal_OnAnimGraphDebugFlow == nullptr)
|
||||
{
|
||||
Internal_OnAnimGraphDebugFlow = ManagedEditor::GetStaticClass()->GetMethod("Internal_OnAnimGraphDebugFlow", 1);
|
||||
ASSERT(Internal_OnAnimGraphDebugFlow);
|
||||
}
|
||||
|
||||
AnimGraphDebugFlowInfo flowInfo;
|
||||
flowInfo.Asset = asset ? asset->GetOrCreateManagedInstance() : nullptr;
|
||||
flowInfo.Object = object ? object->GetOrCreateManagedInstance() : nullptr;
|
||||
flowInfo.NodeId = nodeId;
|
||||
flowInfo.BoxId = boxId;
|
||||
MonoObject* exception = nullptr;
|
||||
void* params[1];
|
||||
params[0] = &flowInfo;
|
||||
Internal_OnAnimGraphDebugFlow->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
{
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Error, TEXT("OnAnimGraphDebugFlow"));
|
||||
}
|
||||
}
|
||||
|
||||
void OnLogMessage(LogType type, const StringView& msg);
|
||||
|
||||
ManagedEditor::ManagedEditor()
|
||||
@@ -186,7 +154,6 @@ ManagedEditor::ManagedEditor()
|
||||
CSG::Builder::OnBrushModified.Bind<OnBrushModified>();
|
||||
Log::Logger::OnMessage.Bind<OnLogMessage>();
|
||||
VisualScripting::DebugFlow.Bind<OnVisualScriptingDebugFlow>();
|
||||
AnimGraphExecutor::DebugFlow.Bind<OnAnimGraphDebugFlow>();
|
||||
}
|
||||
|
||||
ManagedEditor::~ManagedEditor()
|
||||
@@ -203,13 +170,12 @@ ManagedEditor::~ManagedEditor()
|
||||
CSG::Builder::OnBrushModified.Unbind<OnBrushModified>();
|
||||
Log::Logger::OnMessage.Unbind<OnLogMessage>();
|
||||
VisualScripting::DebugFlow.Unbind<OnVisualScriptingDebugFlow>();
|
||||
AnimGraphExecutor::DebugFlow.Unbind<OnAnimGraphDebugFlow>();
|
||||
}
|
||||
|
||||
void ManagedEditor::Init()
|
||||
{
|
||||
// Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time
|
||||
void* args[2];
|
||||
void* args[3];
|
||||
MClass* mclass = GetClass();
|
||||
if (mclass == nullptr)
|
||||
{
|
||||
@@ -230,6 +196,12 @@ void ManagedEditor::Init()
|
||||
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
|
||||
args[0] = &isHeadless;
|
||||
args[1] = &skipCompile;
|
||||
Guid sceneId;
|
||||
if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId)))
|
||||
{
|
||||
sceneId = Guid::Empty;
|
||||
}
|
||||
args[2] = &sceneId;
|
||||
initMethod->Invoke(instance, args, &exception);
|
||||
if (exception)
|
||||
{
|
||||
@@ -481,6 +453,18 @@ bool ManagedEditor::OnAppExit()
|
||||
return MUtils::Unbox<bool>(Internal_OnAppExit->Invoke(GetManagedInstance(), nullptr, nullptr));
|
||||
}
|
||||
|
||||
void ManagedEditor::RequestStartPlayOnEditMode()
|
||||
{
|
||||
if (!HasManagedInstance())
|
||||
return;
|
||||
if (Internal_RequestStartPlayOnEditMode == nullptr)
|
||||
{
|
||||
Internal_RequestStartPlayOnEditMode = GetClass()->GetMethod("Internal_RequestStartPlayOnEditMode");
|
||||
ASSERT(Internal_RequestStartPlayOnEditMode);
|
||||
}
|
||||
Internal_RequestStartPlayOnEditMode->Invoke(GetManagedInstance(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
void ManagedEditor::OnEditorAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
ASSERT(!HasManagedInstance());
|
||||
@@ -511,7 +495,6 @@ void ManagedEditor::DestroyManaged()
|
||||
Internal_GetGameWinPtr = nullptr;
|
||||
Internal_OnAppExit = nullptr;
|
||||
Internal_OnVisualScriptingDebugFlow = nullptr;
|
||||
Internal_OnAnimGraphDebugFlow = nullptr;
|
||||
|
||||
// Base
|
||||
PersistentScriptingObject::DestroyManaged();
|
||||
|
||||
@@ -133,6 +133,11 @@ public:
|
||||
/// <returns>True if exit engine, otherwise false.</returns>
|
||||
bool OnAppExit();
|
||||
|
||||
/// <summary>
|
||||
/// Requests play mode when the editor is in edit mode ( once ).
|
||||
/// </summary>
|
||||
void RequestStartPlayOnEditMode();
|
||||
|
||||
private:
|
||||
|
||||
void OnEditorAssemblyLoaded(MAssembly* assembly);
|
||||
|
||||
@@ -936,23 +936,27 @@ namespace FlaxEditor.Modules
|
||||
Proxy.Add(new SettingsProxy(typeof(PhysicsSettings), Editor.Instance.Icons.PhysicsSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(GraphicsSettings), Editor.Instance.Icons.GraphicsSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(NavigationSettings), Editor.Instance.Icons.NavigationSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(LocalizationSettings), Editor.Instance.Icons.Document128));
|
||||
Proxy.Add(new SettingsProxy(typeof(LocalizationSettings), Editor.Instance.Icons.LocalizationSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(AudioSettings), Editor.Instance.Icons.AudioSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(BuildSettings), Editor.Instance.Icons.BuildSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(InputSettings), Editor.Instance.Icons.InputSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(StreamingSettings), Editor.Instance.Icons.BuildSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(WindowsPlatformSettings), Editor.Instance.Icons.WindowsSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(UWPPlatformSettings), Editor.Instance.Icons.UWPSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(LinuxPlatformSettings), Editor.Instance.Icons.LinuxSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings), Editor.Instance.Icons.AndroidSettings128));
|
||||
|
||||
var typePS4PlatformSettings = TypeUtils.GetManagedType(GameSettings.PS4PlatformSettingsTypename);
|
||||
if (typePS4PlatformSettings != null)
|
||||
Proxy.Add(new SettingsProxy(typePS4PlatformSettings, Editor.Instance.Icons.PlaystationSettings128));
|
||||
|
||||
var typeXboxScarlettPlatformSettings = TypeUtils.GetManagedType(GameSettings.XboxScarlettPlatformSettingsTypename);
|
||||
if (typeXboxScarlettPlatformSettings != null)
|
||||
Proxy.Add(new SettingsProxy(typeXboxScarlettPlatformSettings, Editor.Instance.Icons.XBoxScarletIcon128));
|
||||
Proxy.Add(new SettingsProxy(typeof(AndroidPlatformSettings), Editor.Instance.Icons.AndroidSettings128));
|
||||
|
||||
var typeSwitchPlatformSettings = TypeUtils.GetManagedType(GameSettings.SwitchPlatformSettingsTypename);
|
||||
if (typeSwitchPlatformSettings != null)
|
||||
Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings, Editor.Instance.Icons.Document128));
|
||||
Proxy.Add(new SettingsProxy(typeof(AudioSettings), Editor.Instance.Icons.AudioSettings128));
|
||||
Proxy.Add(new SettingsProxy(typeSwitchPlatformSettings, Editor.Instance.Icons.SwitchSettings128));
|
||||
|
||||
// Last add generic json (won't override other json proxies)
|
||||
Proxy.Add(new GenericJsonAssetProxy());
|
||||
|
||||
@@ -287,11 +287,11 @@ namespace FlaxEditor.Modules
|
||||
break;
|
||||
case ActorNode actorNode:
|
||||
Editor.Instance.SceneEditing.Select(actorNode.Actor);
|
||||
Editor.Instance.Windows.EditWin.ShowSelectedActors();
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
break;
|
||||
case Actor actor:
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
Editor.Instance.Windows.EditWin.ShowSelectedActors();
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +203,7 @@ namespace FlaxEditor.Modules
|
||||
else if (!gameWin.IsSelected)
|
||||
{
|
||||
gameWin.SelectTab(false);
|
||||
gameWin.RootWindow?.Window?.Focus();
|
||||
FlaxEngine.GUI.RootControl.GameRoot.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,6 +151,30 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(typeof(InputBinding), "Q")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1550)]
|
||||
public InputBinding Down = new InputBinding(KeyboardKeys.Q);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad0")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1600)]
|
||||
public InputBinding ViewpointFront = new InputBinding(KeyboardKeys.Numpad0);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad5")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1610)]
|
||||
public InputBinding ViewpointBack = new InputBinding(KeyboardKeys.Numpad5);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad4")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1620)]
|
||||
public InputBinding ViewpointLeft = new InputBinding(KeyboardKeys.Numpad4);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad6")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1630)]
|
||||
public InputBinding ViewpointRight = new InputBinding(KeyboardKeys.Numpad6);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad8")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1640)]
|
||||
public InputBinding ViewpointTop = new InputBinding(KeyboardKeys.Numpad8);
|
||||
|
||||
[DefaultValue(typeof(InputBinding), "Numpad2")]
|
||||
[EditorDisplay("Viewport"), EditorOrder(1650)]
|
||||
public InputBinding ViewpointBottom = new InputBinding(KeyboardKeys.Numpad2);
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
@@ -232,6 +232,7 @@ namespace FlaxEditor.Options
|
||||
BorderNormal = Color.FromBgra(0xFF54545C),
|
||||
TextBoxBackground = Color.FromBgra(0xFF333337),
|
||||
TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46),
|
||||
CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC),
|
||||
ProgressNormal = Color.FromBgra(0xFF0ad328),
|
||||
|
||||
// Fonts
|
||||
|
||||
@@ -10,8 +10,6 @@ namespace FlaxEditor.Progress.Handlers
|
||||
/// <seealso cref="FlaxEditor.Progress.ProgressHandler" />
|
||||
public sealed class BakeLightmapsProgress : ProgressHandler
|
||||
{
|
||||
private static int _canBake;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether GPU lightmaps baking is supported on this device.
|
||||
/// </summary>
|
||||
@@ -19,15 +17,11 @@ namespace FlaxEditor.Progress.Handlers
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_canBake == 0)
|
||||
{
|
||||
var instance = GPUDevice.Instance;
|
||||
if (instance == null)
|
||||
return false;
|
||||
var limits = instance.Limits;
|
||||
_canBake = limits.HasCompute && limits.MaximumTexture2DSize >= 8 * 1024 && instance.TotalGraphicsMemory >= 2 * 1024 ? 1 : 2;
|
||||
}
|
||||
return _canBake == 1;
|
||||
var instance = GPUDevice.Instance;
|
||||
if (instance == null)
|
||||
return false;
|
||||
var limits = instance.Limits;
|
||||
return limits.HasCompute && limits.HasTypedUAVLoad && limits.MaximumTexture2DSize >= 8 * 1024 && instance.TotalGraphicsMemory >= 2 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
public ActorTreeNode()
|
||||
: base(true)
|
||||
{
|
||||
ChildrenIndent = 16.0f;
|
||||
}
|
||||
|
||||
internal virtual void LinkNode(ActorNode node)
|
||||
@@ -292,21 +293,6 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
if (IsFocused)
|
||||
{
|
||||
if (key == KeyboardKeys.F2)
|
||||
{
|
||||
StartRenaming();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override DragDropEffect OnDragEnterHeader(DragData data)
|
||||
{
|
||||
@@ -567,121 +553,12 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
{
|
||||
for (int i = 0; i < _dragAssets.Objects.Count; i++)
|
||||
{
|
||||
var assetItem = _dragAssets.Objects[i];
|
||||
|
||||
if (assetItem.IsOfType<SkinnedModel>())
|
||||
{
|
||||
// Create actor
|
||||
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(assetItem.ID);
|
||||
|
||||
var actor = new AnimatedModel
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
SkinnedModel = model,
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem.IsOfType<Model>())
|
||||
{
|
||||
// Create actor
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(assetItem.ID);
|
||||
|
||||
var actor = new StaticModel
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
Model = model,
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem.IsOfType<CollisionData>())
|
||||
{
|
||||
// Create actor
|
||||
var actor = new MeshCollider
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
CollisionData = FlaxEngine.Content.LoadAsync<CollisionData>(assetItem.ID),
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem.IsOfType<ParticleSystem>())
|
||||
{
|
||||
// Create actor
|
||||
var actor = new ParticleEffect
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
ParticleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(assetItem.ID),
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem.IsOfType<SceneAnimation>())
|
||||
{
|
||||
// Create actor
|
||||
var actor = new SceneAnimationPlayer
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
Animation = FlaxEngine.Content.LoadAsync<SceneAnimation>(assetItem.ID),
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem.IsOfType<AudioClip>())
|
||||
{
|
||||
// Create actor
|
||||
var actor = new AudioSource
|
||||
{
|
||||
StaticFlags = Actor.StaticFlags,
|
||||
Name = assetItem.ShortName,
|
||||
Clip = FlaxEngine.Content.LoadAsync<AudioClip>(assetItem.ID),
|
||||
Transform = Actor.Transform
|
||||
};
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
|
||||
break;
|
||||
}
|
||||
else if (assetItem.IsOfType<Prefab>())
|
||||
{
|
||||
// Create prefab instance
|
||||
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(assetItem.ID);
|
||||
var actor = PrefabManager.SpawnPrefab(prefab, null);
|
||||
actor.StaticFlags = Actor.StaticFlags;
|
||||
actor.Name = assetItem.ShortName;
|
||||
actor.Transform = Actor.Transform;
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
else if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
{
|
||||
// Create actor
|
||||
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
|
||||
actor.StaticFlags = Actor.StaticFlags;
|
||||
actor.Name = assetItem.ShortName;
|
||||
actor.Transform = Actor.Transform;
|
||||
|
||||
// Spawn
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
var item = _dragAssets.Objects[i];
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.StaticFlags = Actor.StaticFlags;
|
||||
actor.Name = item.ShortName;
|
||||
actor.Transform = Actor.Transform;
|
||||
ActorNode.Root.Spawn(actor, Actor);
|
||||
}
|
||||
|
||||
result = DragDropEffect.Move;
|
||||
@@ -736,46 +613,12 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
return actorNode.Actor != null && actorNode != ActorNode && actorNode.Find(Actor) == null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the asset for drag and drop into one of the scene tree nodes.
|
||||
/// </summary>
|
||||
/// <param name="assetItem">The item.</param>
|
||||
/// <returns>True if can drag and drop it, otherwise false.</returns>
|
||||
public static bool ValidateDragAsset(AssetItem assetItem)
|
||||
private bool ValidateDragAsset(AssetItem assetItem)
|
||||
{
|
||||
if (assetItem.IsOfType<SkinnedModel>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<Model>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<AudioClip>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<Prefab>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<CollisionData>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<ParticleSystem>())
|
||||
return true;
|
||||
|
||||
if (assetItem.IsOfType<SceneAnimation>())
|
||||
return true;
|
||||
|
||||
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return assetItem.OnEditorDrag(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the type of the actor for drag and drop into one of the scene tree nodes.
|
||||
/// </summary>
|
||||
/// <param name="actorType">Type of the actor.</param>
|
||||
/// <returns>True if can drag and drop it, otherwise false.</returns>
|
||||
public static bool ValidateDragActorType(ScriptType actorType)
|
||||
private static bool ValidateDragActorType(ScriptType actorType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ void CodeEditingManager::OpenSolution(CodeEditorTypes editorType)
|
||||
const auto editor = GetCodeEditor(editorType);
|
||||
if (editor)
|
||||
{
|
||||
editor->OpenSolution();
|
||||
OpenSolution(editor);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -10,12 +10,24 @@
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include "Engine/Core/Collections/Sorting.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/Win32/IncludeWindowsHeaders.h"
|
||||
#include "Engine/Serialization/Json.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RiderInstallation
|
||||
{
|
||||
String path;
|
||||
String version;
|
||||
|
||||
RiderInstallation(const String& path_, const String& version_)
|
||||
: path(path_), version(version_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
bool FindRegistryKeyItems(HKEY hKey, Array<String>& results)
|
||||
{
|
||||
Char nameBuffer[256];
|
||||
@@ -31,7 +43,7 @@ namespace
|
||||
return true;
|
||||
}
|
||||
|
||||
void SearchDirectory(Array<CodeEditor*>* output, const String& directory)
|
||||
void SearchDirectory(Array<RiderInstallation*>* installations, const String& directory)
|
||||
{
|
||||
if (!FileSystem::DirectoryExists(directory))
|
||||
return;
|
||||
@@ -46,24 +58,29 @@ namespace
|
||||
if (document.HasParseError())
|
||||
return;
|
||||
|
||||
// Find version
|
||||
auto versionMember = document.FindMember("version");
|
||||
if (versionMember == document.MemberEnd())
|
||||
return;
|
||||
|
||||
// Find executable file path
|
||||
auto launchMember = document.FindMember("launch");
|
||||
if (launchMember != document.MemberEnd() && launchMember->value.IsArray() && launchMember->value.Size() > 0)
|
||||
{
|
||||
auto launcherPathMember = launchMember->value[0].FindMember("launcherPath");
|
||||
if (launcherPathMember != launchMember->value[0].MemberEnd())
|
||||
{
|
||||
auto launcherPath = launcherPathMember->value.GetText();
|
||||
auto exePath = directory / launcherPath;
|
||||
if (launcherPath.HasChars() && FileSystem::FileExists(exePath))
|
||||
{
|
||||
output->Add(New<RiderCodeEditor>(exePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (launchMember == document.MemberEnd() || !launchMember->value.IsArray() || launchMember->value.Size() == 0)
|
||||
return;
|
||||
|
||||
auto launcherPathMember = launchMember->value[0].FindMember("launcherPath");
|
||||
if (launcherPathMember == launchMember->value[0].MemberEnd())
|
||||
return;
|
||||
|
||||
auto launcherPath = launcherPathMember->value.GetText();
|
||||
auto exePath = directory / launcherPath;
|
||||
if (!launcherPath.HasChars() || !FileSystem::FileExists(exePath))
|
||||
return;
|
||||
|
||||
installations->Add(New<RiderInstallation>(exePath, versionMember->value.GetText()));
|
||||
}
|
||||
|
||||
void SearchRegistry(Array<CodeEditor*>* output, HKEY root, const Char* key)
|
||||
void SearchRegistry(Array<RiderInstallation*>* installations, HKEY root, const Char* key, const Char* valueName = TEXT(""))
|
||||
{
|
||||
// Open key
|
||||
HKEY keyH;
|
||||
@@ -83,14 +100,14 @@ namespace
|
||||
// Read subkey value
|
||||
DWORD type;
|
||||
DWORD cbData;
|
||||
if (RegQueryValueExW(subKeyH, TEXT(""), nullptr, &type, nullptr, &cbData) != ERROR_SUCCESS || type != REG_SZ)
|
||||
if (RegQueryValueExW(subKeyH, valueName, nullptr, &type, nullptr, &cbData) != ERROR_SUCCESS || type != REG_SZ)
|
||||
{
|
||||
RegCloseKey(subKeyH);
|
||||
continue;
|
||||
}
|
||||
Array<Char> data;
|
||||
data.Resize((int32)cbData / sizeof(Char));
|
||||
if (RegQueryValueExW(subKeyH, TEXT(""), nullptr, nullptr, reinterpret_cast<LPBYTE>(data.Get()), &cbData) != ERROR_SUCCESS)
|
||||
if (RegQueryValueExW(subKeyH, valueName, nullptr, nullptr, reinterpret_cast<LPBYTE>(data.Get()), &cbData) != ERROR_SUCCESS)
|
||||
{
|
||||
RegCloseKey(subKeyH);
|
||||
continue;
|
||||
@@ -98,7 +115,7 @@ namespace
|
||||
|
||||
// Check if it's a valid installation path
|
||||
String path(data.Get(), data.Count() - 1);
|
||||
SearchDirectory(output, path);
|
||||
SearchDirectory(installations, path);
|
||||
|
||||
RegCloseKey(subKeyH);
|
||||
}
|
||||
@@ -108,6 +125,31 @@ namespace
|
||||
}
|
||||
}
|
||||
|
||||
bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i2)
|
||||
{
|
||||
Array<String> values1, values2;
|
||||
i1->version.Split('.', values1);
|
||||
i2->version.Split('.', values2);
|
||||
|
||||
int32 version1[3] = { 0 };
|
||||
int32 version2[3] = { 0 };
|
||||
StringUtils::Parse(values1[0].Get(), &version1[0]);
|
||||
StringUtils::Parse(values1[1].Get(), &version1[1]);
|
||||
StringUtils::Parse(values1[2].Get(), &version1[2]);
|
||||
StringUtils::Parse(values2[0].Get(), &version2[0]);
|
||||
StringUtils::Parse(values2[1].Get(), &version2[1]);
|
||||
StringUtils::Parse(values2[2].Get(), &version2[2]);
|
||||
|
||||
// Compare by MAJOR.MINOR.BUILD
|
||||
if (version1[0] == version2[0])
|
||||
{
|
||||
if (version1[1] == version2[1])
|
||||
return version1[2] > version2[2];
|
||||
return version1[1] > version2[1];
|
||||
}
|
||||
return version1[0] > version2[0];
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RiderCodeEditor::RiderCodeEditor(const String& execPath)
|
||||
@@ -119,8 +161,23 @@ RiderCodeEditor::RiderCodeEditor(const String& execPath)
|
||||
void RiderCodeEditor::FindEditors(Array<CodeEditor*>* output)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
SearchRegistry(output, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
|
||||
SearchRegistry(output, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
|
||||
Array<RiderInstallation*> installations;
|
||||
|
||||
// For versions 2021 or later
|
||||
SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\JetBrains\\Rider"), TEXT("InstallDir"));
|
||||
|
||||
// For versions 2020 or earlier
|
||||
SearchRegistry(&installations, HKEY_CURRENT_USER, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
|
||||
SearchRegistry(&installations, HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\WOW6432Node\\JetBrains\\JetBrains Rider"));
|
||||
|
||||
// Sort found installations by version number
|
||||
Sorting::QuickSort(installations.Get(), installations.Count(), &sortInstallations);
|
||||
|
||||
for (RiderInstallation* installation : installations)
|
||||
{
|
||||
output->Add(New<RiderCodeEditor>(installation->path));
|
||||
Delete(installation);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -152,34 +152,10 @@ public:
|
||||
|
||||
namespace VisualStudio
|
||||
{
|
||||
bool SameFile(HANDLE h1, HANDLE h2)
|
||||
{
|
||||
BY_HANDLE_FILE_INFORMATION bhfi1 = { 0 };
|
||||
BY_HANDLE_FILE_INFORMATION bhfi2 = { 0 };
|
||||
|
||||
if (::GetFileInformationByHandle(h1, &bhfi1) && ::GetFileInformationByHandle(h2, &bhfi2))
|
||||
{
|
||||
return ((bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh) && (bhfi1.nFileIndexLow == bhfi2.nFileIndexLow) && (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AreFilePathsEqual(const wchar_t* path1, const wchar_t* path2)
|
||||
{
|
||||
if (wcscmp(path1, path2) == 0)
|
||||
return true;
|
||||
|
||||
HANDLE file1 = CreateFileW(path1, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
HANDLE file2 = CreateFileW(path2, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
bool result = SameFile(file1, file2);
|
||||
|
||||
CloseHandle(file1);
|
||||
CloseHandle(file2);
|
||||
|
||||
return result;
|
||||
}
|
||||
{
|
||||
return _wcsicmp(path1, path2) == 0;
|
||||
}
|
||||
|
||||
class ConnectionInternal
|
||||
{
|
||||
|
||||
@@ -44,6 +44,7 @@ VisualStudioEditor::VisualStudioEditor(VisualStudioVersion version, const String
|
||||
break;
|
||||
}
|
||||
_solutionPath = Globals::ProjectFolder / Editor::Project->Name + TEXT(".sln");
|
||||
_solutionPath.Replace('/', '\\'); // Use Windows-style path separators
|
||||
}
|
||||
|
||||
void VisualStudioEditor::FindEditors(Array<CodeEditor*>* output)
|
||||
@@ -145,7 +146,9 @@ void VisualStudioEditor::OpenFile(const String& path, int32 line)
|
||||
|
||||
// Open file
|
||||
const VisualStudio::Connection connection(*_CLSID, *_solutionPath);
|
||||
const auto result = connection.OpenFile(*path, line);
|
||||
String tmp = path;
|
||||
tmp.Replace('/', '\\'); // Use Windows-style path separators
|
||||
const auto result = connection.OpenFile(*tmp, line);
|
||||
if (result.Failed())
|
||||
{
|
||||
LOG(Warning, "Cannot open file \'{0}\':{1}. {2}.", path, line, String(result.Message.c_str()));
|
||||
|
||||
@@ -304,7 +304,7 @@ MClass* ScriptsBuilder::FindScript(const StringView& scriptName)
|
||||
GetClassName(mclass->GetFullName(), mclassName);
|
||||
if (className == mclassName)
|
||||
{
|
||||
LOG(Info, "Found {0} type for type {1} (assembly {2})", mclass->ToString(), String(scriptName.Get(), scriptName.Length()), assembly->ToString());
|
||||
LOG(Info, "Found {0} type for type {1} (assembly {2})", String(mclass->GetFullName()), String(scriptName.Get(), scriptName.Length()), assembly->ToString());
|
||||
return mclass;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,6 +293,21 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(1, "Value", true, null, 1),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 6,
|
||||
Title = "Delay",
|
||||
Description = "Delays the graph execution. If delay is 0 then it will pass though.",
|
||||
Flags = NodeFlags.VisualScriptGraph,
|
||||
Size = new Vector2(150, 40),
|
||||
DefaultValues = new object[] { 1.0f },
|
||||
Elements = new[]
|
||||
{
|
||||
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Duration", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(void), 2, true),
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,8 +605,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
MakeBox(0, string.Empty, typeof(void), true);
|
||||
}
|
||||
|
||||
// Update size
|
||||
Resize(Style.Current.FontLarge.MeasureText(Title).X + 30, 20 + (_parameters?.Length * 20 ?? 0));
|
||||
ResizeAuto();
|
||||
}
|
||||
|
||||
private void MakeBox(int id, string text, Type type, bool single = false)
|
||||
|
||||
@@ -118,8 +118,10 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
var cm = new ItemsListContextMenu(180);
|
||||
foreach (var module in modules)
|
||||
{
|
||||
cm.AddItem(new ItemsListContextMenu.Item(module.Title, module.TypeID)
|
||||
cm.AddItem(new ItemsListContextMenu.Item
|
||||
{
|
||||
Name = module.Title,
|
||||
Tag = module.TypeID,
|
||||
TooltipText = module.Description,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -677,19 +677,21 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <inheritdoc />
|
||||
public ThisNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLoaded()
|
||||
{
|
||||
base.OnLoaded();
|
||||
var vss = (VisualScriptSurface)this.Context.Surface;
|
||||
var type = TypeUtils.GetType(vss.Script.ScriptTypeName);
|
||||
|
||||
var surface = (VisualScriptSurface)Context.Surface;
|
||||
var type = TypeUtils.GetType(surface.Script.ScriptTypeName);
|
||||
var box = (OutputBox)GetBox(0);
|
||||
box.CurrentType = type ? type : new ScriptType(typeof(VisualScript));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private class AssetReferenceNode : SurfaceNode
|
||||
{
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace FlaxEditor.Surface
|
||||
/// <summary>
|
||||
/// The box size (with and height).
|
||||
/// </summary>
|
||||
public const float BoxSize = 16.0f;
|
||||
public const float BoxSize = 20.0f;
|
||||
|
||||
/// <summary>
|
||||
/// The node layout offset on the y axis (height of the boxes rows, etc.). It's used to make the design more consistent.
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace FlaxEditor.Surface
|
||||
[HideInEditor]
|
||||
public class ParticleEmitterSurface : VisjectSurface
|
||||
{
|
||||
internal Particles.ParticleEmitterNode _rootNode;
|
||||
internal FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode _rootNode;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the root node of the emitter graph.
|
||||
/// </summary>
|
||||
public Particles.ParticleEmitterNode RootNode => _rootNode;
|
||||
public FlaxEditor.Surface.Archetypes.Particles.ParticleEmitterNode RootNode => _rootNode;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ParticleEmitterSurface(IVisjectSurfaceOwner owner, Action onSave, FlaxEditor.Undo undo)
|
||||
|
||||
@@ -447,18 +447,13 @@ namespace FlaxEditor.Surface
|
||||
var cm = new ItemsListContextMenu(180);
|
||||
foreach (var newParameterType in newParameterTypes)
|
||||
{
|
||||
var name = newParameterType.Type != null ? window.VisjectSurface.GetTypeName(newParameterType) : newParameterType.Name;
|
||||
var item = new ItemsListContextMenu.Item(name, newParameterType)
|
||||
var item = new TypeSearchPopup.TypeItemView(newParameterType)
|
||||
{
|
||||
Tag = newParameterType,
|
||||
TooltipText = newParameterType.TypeName,
|
||||
};
|
||||
var attributes = newParameterType.GetAttributes(false);
|
||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
||||
if (tooltipAttribute != null)
|
||||
{
|
||||
item.TooltipText += '\n';
|
||||
item.TooltipText += tooltipAttribute.Text;
|
||||
}
|
||||
if (newParameterType.Type != null)
|
||||
item.Name = window.VisjectSurface.GetTypeName(newParameterType);
|
||||
cm.AddItem(item);
|
||||
}
|
||||
cm.ItemClicked += OnAddParameterItemClicked;
|
||||
|
||||
@@ -33,6 +33,25 @@ namespace FlaxEditor.Tools.Foliage
|
||||
GizmoMode = mode;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override BoundingSphere FocusBounds
|
||||
{
|
||||
get
|
||||
{
|
||||
var foliage = GizmoMode.SelectedFoliage;
|
||||
if (foliage)
|
||||
{
|
||||
var instanceIndex = GizmoMode.SelectedInstanceIndex;
|
||||
if (instanceIndex >= 0 && instanceIndex < foliage.InstancesCount)
|
||||
{
|
||||
var instance = foliage.GetInstance(instanceIndex);
|
||||
return instance.Bounds;
|
||||
}
|
||||
}
|
||||
return base.FocusBounds;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override int SelectionCount
|
||||
{
|
||||
|
||||
@@ -169,6 +169,9 @@ namespace FlaxEditor.Tools.Foliage
|
||||
PaintEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => IsPainting;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
{
|
||||
|
||||
@@ -135,6 +135,9 @@ namespace FlaxEditor.Tools.Terrain
|
||||
PaintEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => IsPainting;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
{
|
||||
|
||||
@@ -135,6 +135,9 @@ namespace FlaxEditor.Tools.Terrain
|
||||
PaintEnded?.Invoke();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => IsPainting;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "TerrainTools.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Cache.h"
|
||||
#include "Engine/Core/Math/Int2.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace FlaxEditor.Tools.Terrain.Undo
|
||||
{
|
||||
var data = Marshal.AllocHGlobal(_heightmapDataSize);
|
||||
var source = GetData(ref patchCoord, tag);
|
||||
Utils.MemoryCopy(source, data, _heightmapDataSize);
|
||||
Utils.MemoryCopy(data, source, (ulong)_heightmapDataSize);
|
||||
_patches.Add(new PatchData
|
||||
{
|
||||
PatchCoord = patchCoord,
|
||||
@@ -150,7 +150,7 @@ namespace FlaxEditor.Tools.Terrain.Undo
|
||||
|
||||
var data = Marshal.AllocHGlobal(_heightmapDataSize);
|
||||
var source = GetData(ref patch.PatchCoord, patch.Tag);
|
||||
Utils.MemoryCopy(source, data, _heightmapDataSize);
|
||||
Utils.MemoryCopy(data, source, (ulong)_heightmapDataSize);
|
||||
patch.After = data;
|
||||
_patches[i] = patch;
|
||||
}
|
||||
|
||||
@@ -540,6 +540,12 @@ namespace FlaxEditor.Tools
|
||||
_paintUpdateCount = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool IsControllingMouse => IsPainting;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override BoundingSphere FocusBounds => _selectedModel?.Sphere ?? base.FocusBounds;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float dt)
|
||||
{
|
||||
|
||||
@@ -143,13 +143,22 @@ namespace FlaxEditor.Viewport.Cameras
|
||||
ShowSphere(ref mergesSphere, ref orientation);
|
||||
}
|
||||
|
||||
private void ShowSphere(ref BoundingSphere sphere)
|
||||
/// <summary>
|
||||
/// Moves the camera to visualize given world area defined by the sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The sphere.</param>
|
||||
public void ShowSphere(ref BoundingSphere sphere)
|
||||
{
|
||||
var q = new Quaternion(0.424461186f, -0.0940724313f, 0.0443938486f, 0.899451137f);
|
||||
ShowSphere(ref sphere, ref q);
|
||||
}
|
||||
|
||||
private void ShowSphere(ref BoundingSphere sphere, ref Quaternion orientation)
|
||||
/// <summary>
|
||||
/// Moves the camera to visualize given world area defined by the sphere.
|
||||
/// </summary>
|
||||
/// <param name="sphere">The sphere.</param>
|
||||
/// <param name="orientation">The camera orientation.</param>
|
||||
public void ShowSphere(ref BoundingSphere sphere, ref Quaternion orientation)
|
||||
{
|
||||
Vector3 position;
|
||||
if (Viewport.UseOrthographicProjection)
|
||||
|
||||
@@ -73,6 +73,9 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public Undo Undo { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void AddUpdateCallbacks(RootControl root)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEditor.Options;
|
||||
@@ -136,7 +137,7 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
// Input
|
||||
|
||||
private bool _isControllingMouse;
|
||||
private bool _isControllingMouse, _isViewportControllingMouse;
|
||||
private int _deltaFilteringStep;
|
||||
private Vector2 _startPos;
|
||||
private Vector2 _mouseDeltaLast;
|
||||
@@ -649,10 +650,32 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
}
|
||||
|
||||
InputActions.Add(options => options.ViewpointTop, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Top").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointBottom, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Bottom").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointFront, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Front").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointBack, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Back").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointRight, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Right").Orientation)));
|
||||
InputActions.Add(options => options.ViewpointLeft, () => OrientViewport(Quaternion.Euler(EditorViewportCameraViewpointValues.First(vp => vp.Name == "Left").Orientation)));
|
||||
|
||||
// Link for task event
|
||||
task.Begin += OnRenderBegin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this viewport is using mouse currently (eg. user moving objects).
|
||||
/// </summary>
|
||||
protected virtual bool IsControllingMouse => false;
|
||||
|
||||
/// <summary>
|
||||
/// Orients the viewport.
|
||||
/// </summary>
|
||||
/// <param name="orientation">The orientation.</param>
|
||||
protected void OrientViewport(Quaternion orientation)
|
||||
{
|
||||
var quat = orientation;
|
||||
OrientViewport(ref quat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Orients the viewport.
|
||||
/// </summary>
|
||||
@@ -661,12 +684,12 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
if (ViewportCamera is FPSCamera fpsCamera)
|
||||
{
|
||||
var pos = Vector3.Zero + Vector3.Backward * orientation * 2000.0f;
|
||||
var pos = ViewPosition + Vector3.Backward * orientation * 2000.0f;
|
||||
fpsCamera.MoveViewport(pos, orientation);
|
||||
}
|
||||
else
|
||||
{
|
||||
ViewportCamera.SetArcBallView(orientation, Vector3.Zero, 2000.0f);
|
||||
ViewportCamera.SetArcBallView(orientation, ViewPosition, 2000.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,7 +995,16 @@ namespace FlaxEditor.Viewport
|
||||
// Update input
|
||||
{
|
||||
// Get input buttons and keys (skip if viewport has no focus or mouse is over a child control)
|
||||
bool useMouse = Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height);
|
||||
var isViewportControllingMouse = IsControllingMouse;
|
||||
if (isViewportControllingMouse != _isViewportControllingMouse)
|
||||
{
|
||||
_isViewportControllingMouse = isViewportControllingMouse;
|
||||
if (isViewportControllingMouse)
|
||||
StartMouseCapture();
|
||||
else
|
||||
EndMouseCapture();
|
||||
}
|
||||
bool useMouse = IsControllingMouse || (Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height));
|
||||
_prevInput = _input;
|
||||
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl));
|
||||
if (ContainsFocus && hit == null)
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace FlaxEditor.Viewport
|
||||
/// Main editor gizmo viewport used by the <see cref="EditGameWindow"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Viewport.EditorGizmoViewport" />
|
||||
public partial class MainEditorGizmoViewport : EditorGizmoViewport, IEditorPrimitivesOwner
|
||||
public partial class MainEditorGizmoViewport : EditorGizmoViewport, IEditorPrimitivesOwner, IGizmoOwner
|
||||
{
|
||||
private readonly Editor _editor;
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace FlaxEditor.Viewport
|
||||
private readonly ViewportWidgetButton _rotateSnapping;
|
||||
private readonly ViewportWidgetButton _scaleSnapping;
|
||||
|
||||
private readonly DragAssets<DragDropEventArgs> _dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
||||
private readonly DragAssets<DragDropEventArgs> _dragAssets;
|
||||
private readonly DragActorType<DragDropEventArgs> _dragActorType = new DragActorType<DragDropEventArgs>(ValidateDragActorType);
|
||||
|
||||
private SelectionOutline _customSelectionOutline;
|
||||
@@ -187,6 +187,7 @@ namespace FlaxEditor.Viewport
|
||||
: base(Object.New<SceneRenderTask>(), editor.Undo)
|
||||
{
|
||||
_editor = editor;
|
||||
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
||||
|
||||
// Prepare rendering task
|
||||
Task.ActorsSource = ActorsSources.Scenes;
|
||||
@@ -360,7 +361,7 @@ namespace FlaxEditor.Viewport
|
||||
InputActions.Add(options => options.TranslateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||
InputActions.Add(options => options.RotateMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||
InputActions.Add(options => options.ScaleMode, () => TransformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||
InputActions.Add(options => options.FocusSelection, () => _editor.Windows.EditWin.ShowSelectedActors());
|
||||
InputActions.Add(options => options.FocusSelection, FocusSelection);
|
||||
InputActions.Add(options => options.Delete, _editor.SceneEditing.Delete);
|
||||
}
|
||||
|
||||
@@ -449,6 +450,12 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public void DrawEditorPrimitives(GPUContext context, ref RenderContext renderContext, GPUTexture target, GPUTexture targetDepth)
|
||||
{
|
||||
// Draw gizmos
|
||||
for (int i = 0; i < Gizmos.Count; i++)
|
||||
{
|
||||
Gizmos[i].Draw(ref renderContext);
|
||||
}
|
||||
|
||||
// Draw selected objects debug shapes and visuals
|
||||
if (DrawDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw)
|
||||
{
|
||||
@@ -651,6 +658,31 @@ namespace FlaxEditor.Viewport
|
||||
Gizmos.ForEach(x => x.OnSelectionChanged(selection));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
public void FocusSelection()
|
||||
{
|
||||
var orientation = ViewOrientation;
|
||||
FocusSelection(ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
/// <param name="orientation">The target view orientation.</param>
|
||||
public void FocusSelection(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count == 0)
|
||||
return;
|
||||
|
||||
var gizmoBounds = Gizmos.Active.FocusBounds;
|
||||
if (gizmoBounds != BoundingSphere.Empty)
|
||||
((FPSCamera)ViewportCamera).ShowSphere(ref gizmoBounds, ref orientation);
|
||||
else
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the transform to the collection of scene graph nodes.
|
||||
/// </summary>
|
||||
@@ -709,11 +741,9 @@ namespace FlaxEditor.Viewport
|
||||
protected override void OrientViewport(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count != 0)
|
||||
{
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orientation);
|
||||
}
|
||||
|
||||
base.OrientViewport(ref orientation);
|
||||
FocusSelection(ref orientation);
|
||||
else
|
||||
base.OrientViewport(ref orientation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -800,31 +830,19 @@ namespace FlaxEditor.Viewport
|
||||
return result;
|
||||
}
|
||||
|
||||
private static bool ValidateDragItem(ContentItem contentItem)
|
||||
private bool ValidateDragItem(ContentItem contentItem)
|
||||
{
|
||||
if (!Level.IsAnySceneLoaded)
|
||||
return false;
|
||||
|
||||
if (contentItem is AssetItem assetItem)
|
||||
{
|
||||
if (assetItem.IsOfType<ParticleSystem>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<SceneAnimation>())
|
||||
if (assetItem.OnEditorDrag(this))
|
||||
return true;
|
||||
if (assetItem.IsOfType<MaterialBase>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<ModelBase>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<CollisionData>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<AudioClip>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<Prefab>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<SceneAsset>())
|
||||
return true;
|
||||
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -891,119 +909,40 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private void Spawn(AssetItem item, SceneGraphNode hit, ref Vector2 location, ref Vector3 hitLocation)
|
||||
{
|
||||
if (item is AssetItem assetItem)
|
||||
if (item.IsOfType<MaterialBase>())
|
||||
{
|
||||
if (assetItem.IsOfType<ParticleSystem>())
|
||||
if (hit is StaticModelNode staticModelNode)
|
||||
{
|
||||
var asset = FlaxEngine.Content.LoadAsync<ParticleSystem>(item.ID);
|
||||
var actor = new ParticleEffect
|
||||
{
|
||||
Name = item.ShortName,
|
||||
ParticleSystem = asset
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<SceneAnimation>())
|
||||
{
|
||||
var asset = FlaxEngine.Content.LoadAsync<SceneAnimation>(item.ID);
|
||||
var actor = new SceneAnimationPlayer
|
||||
{
|
||||
Name = item.ShortName,
|
||||
Animation = asset
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<MaterialBase>())
|
||||
{
|
||||
if (hit is StaticModelNode staticModelNode)
|
||||
{
|
||||
var staticModel = (StaticModel)staticModelNode.Actor;
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
|
||||
{
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
|
||||
using (new UndoBlock(Undo, staticModel, "Change material"))
|
||||
staticModel.SetMaterial(entryIndex, material);
|
||||
}
|
||||
}
|
||||
else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
|
||||
var staticModel = (StaticModel)staticModelNode.Actor;
|
||||
var ray = ConvertMouseToRay(ref location);
|
||||
if (staticModel.IntersectsEntry(ref ray, out _, out _, out var entryIndex))
|
||||
{
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
|
||||
using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
|
||||
{
|
||||
var surface = brushSurfaceNode.Surface;
|
||||
surface.Material = material;
|
||||
brushSurfaceNode.Surface = surface;
|
||||
}
|
||||
using (new UndoBlock(Undo, staticModel, "Change material"))
|
||||
staticModel.SetMaterial(entryIndex, material);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<SkinnedModel>())
|
||||
else if (hit is BoxBrushNode.SideLinkNode brushSurfaceNode)
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(item.ID);
|
||||
var actor = new AnimatedModel
|
||||
var material = FlaxEngine.Content.LoadAsync<MaterialBase>(item.ID);
|
||||
using (new UndoBlock(Undo, brushSurfaceNode.Brush, "Change material"))
|
||||
{
|
||||
Name = item.ShortName,
|
||||
SkinnedModel = model
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<Model>())
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(item.ID);
|
||||
var actor = new StaticModel
|
||||
{
|
||||
Name = item.ShortName,
|
||||
Model = model
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<CollisionData>())
|
||||
{
|
||||
var collisionData = FlaxEngine.Content.LoadAsync<CollisionData>(item.ID);
|
||||
var actor = new MeshCollider
|
||||
{
|
||||
Name = item.ShortName,
|
||||
CollisionData = collisionData
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<AudioClip>())
|
||||
{
|
||||
var clip = FlaxEngine.Content.LoadAsync<AudioClip>(item.ID);
|
||||
var actor = new AudioSource
|
||||
{
|
||||
Name = item.ShortName,
|
||||
Clip = clip
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<Prefab>())
|
||||
{
|
||||
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(item.ID);
|
||||
var actor = PrefabManager.SpawnPrefab(prefab, null);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (assetItem.IsOfType<SceneAsset>())
|
||||
{
|
||||
Editor.Instance.Scene.OpenScene(item.ID, true);
|
||||
return;
|
||||
}
|
||||
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
{
|
||||
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
var surface = brushSurfaceNode.Surface;
|
||||
surface.Material = material;
|
||||
brushSurfaceNode.Surface = surface;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (item.IsOfType<SceneAsset>())
|
||||
{
|
||||
Editor.Instance.Scene.OpenScene(item.ID, true);
|
||||
return;
|
||||
}
|
||||
{
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace FlaxEditor.Viewport
|
||||
/// <seealso cref="PrefabWindow" />
|
||||
/// <seealso cref="PrefabPreview" />
|
||||
/// <seealso cref="IGizmoOwner" />
|
||||
public class PrefabWindowViewport : PrefabPreview, IEditorPrimitivesOwner
|
||||
public class PrefabWindowViewport : PrefabPreview, IGizmoOwner
|
||||
{
|
||||
[HideInEditor]
|
||||
private sealed class PrefabSpritesRenderer : MainEditorGizmoViewport.EditorSpritesRenderer
|
||||
@@ -51,9 +51,8 @@ namespace FlaxEditor.Viewport
|
||||
private ViewportWidgetButton _scaleSnapping;
|
||||
|
||||
private readonly ViewportDebugDrawData _debugDrawData = new ViewportDebugDrawData(32);
|
||||
private IntPtr _debugDrawContext;
|
||||
private PrefabSpritesRenderer _spritesRenderer;
|
||||
private readonly DragAssets _dragAssets = new DragAssets(ValidateDragItem);
|
||||
private readonly DragAssets _dragAssets;
|
||||
private readonly DragActorType _dragActorType = new DragActorType(ValidateDragActorType);
|
||||
private readonly DragHandlers _dragHandlers = new DragHandlers();
|
||||
|
||||
@@ -67,16 +66,6 @@ namespace FlaxEditor.Viewport
|
||||
/// </summary>
|
||||
public SelectionOutline SelectionOutline;
|
||||
|
||||
/// <summary>
|
||||
/// The editor primitives postFx.
|
||||
/// </summary>
|
||||
public EditorPrimitives EditorPrimitives;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether draw <see cref="DebugDraw"/> shapes.
|
||||
/// </summary>
|
||||
public bool DrawDebugDraw = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PrefabWindowViewport"/> class.
|
||||
/// </summary>
|
||||
@@ -88,7 +77,9 @@ namespace FlaxEditor.Viewport
|
||||
_window.SelectionChanged += OnSelectionChanged;
|
||||
Undo = window.Undo;
|
||||
ViewportCamera = new FPSCamera();
|
||||
_debugDrawContext = DebugDraw.AllocateContext();
|
||||
_dragAssets = new DragAssets(ValidateDragItem);
|
||||
ShowDebugDraw = true;
|
||||
ShowEditorPrimitives = true;
|
||||
|
||||
// Prepare rendering task
|
||||
Task.ActorsSource = ActorsSources.CustomActors;
|
||||
@@ -101,9 +92,6 @@ namespace FlaxEditor.Viewport
|
||||
SelectionOutline = FlaxEngine.Object.New<SelectionOutline>();
|
||||
SelectionOutline.SelectionGetter = () => TransformGizmo.SelectedParents;
|
||||
Task.CustomPostFx.Add(SelectionOutline);
|
||||
EditorPrimitives = FlaxEngine.Object.New<EditorPrimitives>();
|
||||
EditorPrimitives.Viewport = this;
|
||||
Task.CustomPostFx.Add(EditorPrimitives);
|
||||
_spritesRenderer = FlaxEngine.Object.New<PrefabSpritesRenderer>();
|
||||
_spritesRenderer.Task = Task;
|
||||
_spritesRenderer.Viewport = this;
|
||||
@@ -281,13 +269,6 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
var task = renderContext.Task;
|
||||
|
||||
// Render editor primitives, gizmo and debug shapes in debug view modes
|
||||
// Note: can use Output buffer as both input and output because EditorPrimitives is using a intermediate buffers
|
||||
if (EditorPrimitives && EditorPrimitives.CanRender)
|
||||
{
|
||||
EditorPrimitives.Render(context, ref renderContext, task.Output, task.Output);
|
||||
}
|
||||
|
||||
// Render editor sprites
|
||||
if (_spritesRenderer && _spritesRenderer.CanRender)
|
||||
{
|
||||
@@ -315,7 +296,8 @@ namespace FlaxEditor.Viewport
|
||||
/// </summary>
|
||||
public void ShowSelectedActors()
|
||||
{
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents);
|
||||
var orient = Viewport.ViewOrientation;
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orient);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -354,6 +336,12 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public Undo Undo { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public EditorViewport Viewport => this;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void AddUpdateCallbacks(RootControl root)
|
||||
{
|
||||
@@ -673,24 +661,14 @@ namespace FlaxEditor.Viewport
|
||||
return _dragHandlers.OnDragEnter(data);
|
||||
}
|
||||
|
||||
private static bool ValidateDragItem(ContentItem contentItem)
|
||||
private bool ValidateDragItem(ContentItem contentItem)
|
||||
{
|
||||
if (contentItem is AssetItem assetItem)
|
||||
{
|
||||
if (assetItem.IsOfType<ParticleSystem>())
|
||||
if (assetItem.OnEditorDrag(this))
|
||||
return true;
|
||||
if (assetItem.IsOfType<MaterialBase>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<ModelBase>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<CollisionData>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<AudioClip>())
|
||||
return true;
|
||||
if (assetItem.IsOfType<Prefab>())
|
||||
return true;
|
||||
if (assetItem is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -743,17 +721,6 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
if (item is BinaryAssetItem binaryAssetItem)
|
||||
{
|
||||
if (binaryAssetItem.Type == typeof(ParticleSystem))
|
||||
{
|
||||
var particleSystem = FlaxEngine.Content.LoadAsync<ParticleSystem>(item.ID);
|
||||
var actor = new ParticleEffect
|
||||
{
|
||||
Name = item.ShortName,
|
||||
ParticleSystem = particleSystem
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (typeof(MaterialBase).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
if (hit is StaticModelNode staticModelNode)
|
||||
@@ -769,65 +736,11 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (typeof(SkinnedModel).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<SkinnedModel>(item.ID);
|
||||
var actor = new AnimatedModel
|
||||
{
|
||||
Name = item.ShortName,
|
||||
SkinnedModel = model
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (typeof(Model).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
var model = FlaxEngine.Content.LoadAsync<Model>(item.ID);
|
||||
var actor = new StaticModel
|
||||
{
|
||||
Name = item.ShortName,
|
||||
Model = model
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (binaryAssetItem.IsOfType<CollisionData>())
|
||||
{
|
||||
var collisionData = FlaxEngine.Content.LoadAsync<CollisionData>(item.ID);
|
||||
var actor = new MeshCollider
|
||||
{
|
||||
Name = item.ShortName,
|
||||
CollisionData = collisionData
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (typeof(AudioClip).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
var clip = FlaxEngine.Content.LoadAsync<AudioClip>(item.ID);
|
||||
var actor = new AudioSource
|
||||
{
|
||||
Name = item.ShortName,
|
||||
Clip = clip
|
||||
};
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
if (typeof(Prefab).IsAssignableFrom(binaryAssetItem.Type))
|
||||
{
|
||||
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(item.ID);
|
||||
var actor = PrefabManager.SpawnPrefab(prefab, null);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (item is VisualScriptItem visualScriptItem && new ScriptType(typeof(Actor)).IsAssignableFrom(visualScriptItem.ScriptType) && visualScriptItem.ScriptType.CanCreateInstance)
|
||||
{
|
||||
var actor = (Actor)visualScriptItem.ScriptType.CreateInstance();
|
||||
var actor = item.OnEditorDrop(this);
|
||||
actor.Name = item.ShortName;
|
||||
Spawn(actor, ref hitLocation);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,15 +763,38 @@ namespace FlaxEditor.Viewport
|
||||
Spawn(actor, ref hitLocation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
public void FocusSelection()
|
||||
{
|
||||
var orientation = ViewOrientation;
|
||||
FocusSelection(ref orientation);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Focuses the viewport on the current selection of the gizmo.
|
||||
/// </summary>
|
||||
/// <param name="orientation">The target view orientation.</param>
|
||||
public void FocusSelection(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count == 0)
|
||||
return;
|
||||
|
||||
var gizmoBounds = Gizmos.Active.FocusBounds;
|
||||
if (gizmoBounds != BoundingSphere.Empty)
|
||||
((FPSCamera)ViewportCamera).ShowSphere(ref gizmoBounds, ref orientation);
|
||||
else
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orientation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OrientViewport(ref Quaternion orientation)
|
||||
{
|
||||
if (TransformGizmo.SelectedParents.Count != 0)
|
||||
{
|
||||
((FPSCamera)ViewportCamera).ShowActors(TransformGizmo.SelectedParents, ref orientation);
|
||||
}
|
||||
|
||||
base.OrientViewport(ref orientation);
|
||||
FocusSelection(ref orientation);
|
||||
else
|
||||
base.OrientViewport(ref orientation);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -920,35 +856,35 @@ namespace FlaxEditor.Viewport
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_debugDrawContext != IntPtr.Zero)
|
||||
{
|
||||
DebugDraw.FreeContext(_debugDrawContext);
|
||||
_debugDrawContext = IntPtr.Zero;
|
||||
}
|
||||
FlaxEngine.Object.Destroy(ref SelectionOutline);
|
||||
FlaxEngine.Object.Destroy(ref EditorPrimitives);
|
||||
FlaxEngine.Object.Destroy(ref _spritesRenderer);
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void DrawEditorPrimitives(GPUContext context, ref RenderContext renderContext, GPUTexture target, GPUTexture targetDepth)
|
||||
public override void DrawEditorPrimitives(GPUContext context, ref RenderContext renderContext, GPUTexture target, GPUTexture targetDepth)
|
||||
{
|
||||
// Draw selected objects debug shapes and visuals
|
||||
if (DrawDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw)
|
||||
// Draw gizmos
|
||||
for (int i = 0; i < Gizmos.Count; i++)
|
||||
{
|
||||
DebugDraw.SetContext(_debugDrawContext);
|
||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Engine.FramesPerSecond);
|
||||
unsafe
|
||||
Gizmos[i].Draw(ref renderContext);
|
||||
}
|
||||
|
||||
base.DrawEditorPrimitives(context, ref renderContext, target, targetDepth);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext)
|
||||
{
|
||||
base.OnDebugDraw(context, ref renderContext);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (IntPtr* actors = _debugDrawData.ActorsPtrs)
|
||||
{
|
||||
fixed (IntPtr* actors = _debugDrawData.ActorsPtrs)
|
||||
{
|
||||
DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false);
|
||||
}
|
||||
DebugDraw.DrawActors(new IntPtr(actors), _debugDrawData.ActorsCount, false);
|
||||
}
|
||||
DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true);
|
||||
DebugDraw.SetContext(IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEngine;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using Object = FlaxEngine.Object;
|
||||
@@ -13,12 +13,9 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <seealso cref="AssetPreview" />
|
||||
public class AnimatedModelPreview : AssetPreview
|
||||
{
|
||||
private ContextMenuButton _showBoundsButton;
|
||||
private AnimatedModel _previewModel;
|
||||
private StaticModel _previewNodesActor;
|
||||
private Model _previewNodesModel;
|
||||
private int _previewNodesCounter;
|
||||
private List<Vector3> _previewNodesVB;
|
||||
private List<int> _previewNodesIB;
|
||||
private bool _showNodes, _showBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the skinned model asset to preview.
|
||||
@@ -42,7 +39,32 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show animated model skeleton nodes debug view.
|
||||
/// </summary>
|
||||
public bool ShowNodes { get; set; } = false;
|
||||
public bool ShowNodes
|
||||
{
|
||||
get => _showNodes;
|
||||
set
|
||||
{
|
||||
_showNodes = value;
|
||||
if (value)
|
||||
ShowDebugDraw = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show animated model bounding box debug view.
|
||||
/// </summary>
|
||||
public bool ShowBounds
|
||||
{
|
||||
get => _showBounds;
|
||||
set
|
||||
{
|
||||
_showBounds = value;
|
||||
if (value)
|
||||
ShowDebugDraw = true;
|
||||
if (_showBoundsButton != null)
|
||||
_showBoundsButton.Checked = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether scale the model to the normalized bounds.
|
||||
@@ -72,20 +94,14 @@ namespace FlaxEditor.Viewport.Previews
|
||||
UpdateMode = AnimatedModel.AnimationUpdateMode.Manual
|
||||
};
|
||||
|
||||
_previewNodesModel = FlaxEngine.Content.CreateVirtualAsset<Model>();
|
||||
_previewNodesModel.SetupLODs(new[] { 1 });
|
||||
_previewNodesActor = new StaticModel
|
||||
{
|
||||
Model = _previewNodesModel
|
||||
};
|
||||
_previewNodesActor.SetMaterial(0, FlaxEngine.Content.LoadAsyncInternal<MaterialBase>(EditorAssets.WiresDebugMaterial));
|
||||
|
||||
// Link actors for rendering
|
||||
Task.AddCustomActor(_previewModel);
|
||||
Task.AddCustomActor(_previewNodesActor);
|
||||
|
||||
if (useWidgets)
|
||||
{
|
||||
// Show Bounds
|
||||
_showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds);
|
||||
|
||||
// Preview LOD
|
||||
{
|
||||
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
||||
@@ -121,6 +137,55 @@ namespace FlaxEditor.Viewport.Previews
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext)
|
||||
{
|
||||
base.OnDebugDraw(context, ref renderContext);
|
||||
|
||||
// Draw skeleton nodes
|
||||
if (_showNodes)
|
||||
{
|
||||
_previewModel.GetCurrentPose(out var pose);
|
||||
var nodes = _previewModel.SkinnedModel?.Nodes;
|
||||
if (pose != null && pose.Length != 0 && nodes != null)
|
||||
{
|
||||
// Draw bounding box at the node locations
|
||||
var nodesMask = NodesMask != null && NodesMask.Length == nodes.Length ? NodesMask : null;
|
||||
var localBox = new OrientedBoundingBox(new Vector3(-1.0f), new Vector3(1.0f));
|
||||
for (int nodeIndex = 0; nodeIndex < pose.Length; nodeIndex++)
|
||||
{
|
||||
if (nodesMask != null && !nodesMask[nodeIndex])
|
||||
continue;
|
||||
var transform = pose[nodeIndex];
|
||||
transform.Decompose(out var scale, out Matrix _, out _);
|
||||
transform = Matrix.Invert(Matrix.Scaling(scale)) * transform;
|
||||
var box = localBox * transform;
|
||||
DebugDraw.DrawWireBox(box, Color.Green, 0, false);
|
||||
}
|
||||
|
||||
// Nodes connections
|
||||
for (int nodeIndex = 0; nodeIndex < nodes.Length; nodeIndex++)
|
||||
{
|
||||
int parentIndex = nodes[nodeIndex].ParentIndex;
|
||||
if (parentIndex != -1)
|
||||
{
|
||||
if (nodesMask != null && (!nodesMask[nodeIndex] || !nodesMask[parentIndex]))
|
||||
continue;
|
||||
var parentPos = pose[parentIndex].TranslationVector;
|
||||
var bonePos = pose[nodeIndex].TranslationVector;
|
||||
DebugDraw.DrawLine(parentPos, bonePos, Color.Green, 0, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Draw bounds
|
||||
if (_showBounds)
|
||||
{
|
||||
DebugDraw.DrawWireBox(_previewModel.Box, Color.Violet.RGBMultiplied(0.8f), 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
@@ -131,122 +196,6 @@ namespace FlaxEditor.Viewport.Previews
|
||||
{
|
||||
_previewModel.UpdateAnimation();
|
||||
}
|
||||
|
||||
// Update the nodes debug (once every few frames)
|
||||
_previewNodesActor.Transform = _previewModel.Transform;
|
||||
var updateNodesCount = PlayAnimation || _previewNodesVB?.Count == 0 ? 1 : 10;
|
||||
_previewNodesActor.IsActive = ShowNodes;
|
||||
if (_previewNodesCounter++ % updateNodesCount == 0 && ShowNodes)
|
||||
{
|
||||
_previewModel.GetCurrentPose(out var pose);
|
||||
var nodes = _previewModel.SkinnedModel?.Nodes;
|
||||
if (pose == null || pose.Length == 0 || nodes == null)
|
||||
{
|
||||
_previewNodesActor.IsActive = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_previewNodesVB == null)
|
||||
_previewNodesVB = new List<Vector3>(1024 * 2);
|
||||
else
|
||||
_previewNodesVB.Clear();
|
||||
if (_previewNodesIB == null)
|
||||
_previewNodesIB = new List<int>(1024 * 3);
|
||||
else
|
||||
_previewNodesIB.Clear();
|
||||
|
||||
// Draw bounding box at the node locations
|
||||
var nodesMask = NodesMask != null && NodesMask.Length == nodes.Length ? NodesMask : null;
|
||||
var localBox = new OrientedBoundingBox(new Vector3(-1.0f), new Vector3(1.0f));
|
||||
for (int nodeIndex = 0; nodeIndex < pose.Length; nodeIndex++)
|
||||
{
|
||||
if (nodesMask != null && !nodesMask[nodeIndex])
|
||||
continue;
|
||||
|
||||
var transform = pose[nodeIndex];
|
||||
transform.Decompose(out var scale, out Matrix _, out _);
|
||||
transform = Matrix.Invert(Matrix.Scaling(scale)) * transform;
|
||||
|
||||
// Some inlined code to improve performance
|
||||
var box = localBox * transform;
|
||||
//
|
||||
var iStart = _previewNodesVB.Count;
|
||||
box.GetCorners(_previewNodesVB);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
_previewNodesIB.Add(iStart + 4);
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
_previewNodesIB.Add(iStart + 2);
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
_previewNodesIB.Add(iStart + 5);
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 2);
|
||||
_previewNodesIB.Add(iStart + 3);
|
||||
_previewNodesIB.Add(iStart + 2);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 2);
|
||||
_previewNodesIB.Add(iStart + 6);
|
||||
_previewNodesIB.Add(iStart + 2);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 3);
|
||||
_previewNodesIB.Add(iStart + 7);
|
||||
_previewNodesIB.Add(iStart + 3);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 4);
|
||||
_previewNodesIB.Add(iStart + 5);
|
||||
_previewNodesIB.Add(iStart + 4);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 4);
|
||||
_previewNodesIB.Add(iStart + 7);
|
||||
_previewNodesIB.Add(iStart + 4);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 5);
|
||||
_previewNodesIB.Add(iStart + 6);
|
||||
_previewNodesIB.Add(iStart + 5);
|
||||
//
|
||||
_previewNodesIB.Add(iStart + 6);
|
||||
_previewNodesIB.Add(iStart + 7);
|
||||
_previewNodesIB.Add(iStart + 6);
|
||||
//
|
||||
}
|
||||
|
||||
// Nodes connections
|
||||
for (int nodeIndex = 0; nodeIndex < nodes.Length; nodeIndex++)
|
||||
{
|
||||
int parentIndex = nodes[nodeIndex].ParentIndex;
|
||||
|
||||
if (parentIndex != -1)
|
||||
{
|
||||
if (nodesMask != null && (!nodesMask[nodeIndex] || !nodesMask[parentIndex]))
|
||||
continue;
|
||||
|
||||
var parentPos = pose[parentIndex].TranslationVector;
|
||||
var bonePos = pose[nodeIndex].TranslationVector;
|
||||
|
||||
var iStart = _previewNodesVB.Count;
|
||||
_previewNodesVB.Add(parentPos);
|
||||
_previewNodesVB.Add(bonePos);
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
_previewNodesIB.Add(iStart + 1);
|
||||
_previewNodesIB.Add(iStart + 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (_previewNodesIB.Count > 0)
|
||||
_previewNodesModel.LODs[0].Meshes[0].UpdateMesh(_previewNodesVB, _previewNodesIB);
|
||||
else
|
||||
_previewNodesActor.IsActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -265,11 +214,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
// Ensure to cleanup created actor objects
|
||||
_previewNodesActor.Model = null;
|
||||
Object.Destroy(ref _previewModel);
|
||||
Object.Destroy(ref _previewNodesActor);
|
||||
Object.Destroy(ref _previewNodesModel);
|
||||
NodesMask = null;
|
||||
|
||||
base.OnDestroy();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using FlaxEditor.Gizmo;
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.Viewport.Cameras;
|
||||
using FlaxEngine;
|
||||
@@ -11,9 +13,13 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// Generic asset preview editor viewport base class.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.Viewport.EditorViewport" />
|
||||
public abstract class AssetPreview : EditorViewport
|
||||
public abstract class AssetPreview : EditorViewport, IEditorPrimitivesOwner
|
||||
{
|
||||
private ContextMenuButton _showDefaultSceneButton;
|
||||
private IntPtr _debugDrawContext;
|
||||
private bool _debugDrawEnable;
|
||||
private bool _editorPrimitivesEnable;
|
||||
private EditorPrimitives _editorPrimitives;
|
||||
|
||||
/// <summary>
|
||||
/// The preview light. Allows to modify rendering settings.
|
||||
@@ -61,6 +67,61 @@ namespace FlaxEditor.Viewport.Previews
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether draw <see cref="DebugDraw"/> shapes.
|
||||
/// </summary>
|
||||
public bool ShowDebugDraw
|
||||
{
|
||||
get => _debugDrawEnable;
|
||||
set
|
||||
{
|
||||
if (_debugDrawEnable == value)
|
||||
return;
|
||||
_debugDrawEnable = value;
|
||||
if (_debugDrawContext == IntPtr.Zero)
|
||||
{
|
||||
_debugDrawContext = DebugDraw.AllocateContext();
|
||||
var view = Task.View;
|
||||
view.Flags |= ViewFlags.DebugDraw;
|
||||
Task.View = view;
|
||||
}
|
||||
if (value)
|
||||
{
|
||||
// Need to show editor primitives to show debug shapes
|
||||
ShowEditorPrimitives = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether draw <see cref="DebugDraw"/> shapes and other editor primitives such as gizmos.
|
||||
/// </summary>
|
||||
public bool ShowEditorPrimitives
|
||||
{
|
||||
get => _editorPrimitivesEnable;
|
||||
set
|
||||
{
|
||||
if (_editorPrimitivesEnable == value)
|
||||
return;
|
||||
_editorPrimitivesEnable = value;
|
||||
if (_editorPrimitives == null)
|
||||
{
|
||||
_editorPrimitives = Object.New<EditorPrimitives>();
|
||||
_editorPrimitives.Viewport = this;
|
||||
Task.CustomPostFx.Add(_editorPrimitives);
|
||||
Task.PostRender += OnPostRender;
|
||||
var view = Task.View;
|
||||
view.Flags |= ViewFlags.CustomPostProcess;
|
||||
Task.View = view;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the editor primitives renderer. Valid only if <see cref="ShowEditorPrimitives"/> is true.
|
||||
/// </summary>
|
||||
public EditorPrimitives EditorPrimitives => _editorPrimitives;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AssetPreview"/> class.
|
||||
/// </summary>
|
||||
@@ -114,7 +175,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
SunPower = 9.0f
|
||||
};
|
||||
//
|
||||
SkyLight = new SkyLight()
|
||||
SkyLight = new SkyLight
|
||||
{
|
||||
Mode = SkyLight.Modes.CustomTexture,
|
||||
Brightness = 2.1f,
|
||||
@@ -135,20 +196,58 @@ namespace FlaxEditor.Viewport.Previews
|
||||
Task.AddCustomActor(PostFxVolume);
|
||||
}
|
||||
|
||||
private void OnPostRender(GPUContext context, RenderContext renderContext)
|
||||
{
|
||||
if (renderContext.View.Mode != ViewMode.Default && _editorPrimitives && _editorPrimitives.CanRender)
|
||||
{
|
||||
// Render editor primitives, gizmo and debug shapes in debug view modes
|
||||
// Note: can use Output buffer as both input and output because EditorPrimitives is using a intermediate buffers
|
||||
_editorPrimitives.Render(context, ref renderContext, renderContext.Task.Output, renderContext.Task.Output);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when drawing debug shapes with <see cref="DebugDraw"/> for this viewport.
|
||||
/// </summary>
|
||||
/// <param name="context">The GPU context.</param>
|
||||
/// <param name="renderContext">The render context.</param>
|
||||
protected virtual void OnDebugDraw(GPUContext context, ref RenderContext renderContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool HasLoadedAssets => base.HasLoadedAssets && Sky.HasContentLoaded && EnvProbe.Probe.IsLoaded && PostFxVolume.HasContentLoaded;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
// Ensure to cleanup created actor objects
|
||||
Object.Destroy(ref PreviewLight);
|
||||
Object.Destroy(ref EnvProbe);
|
||||
Object.Destroy(ref Sky);
|
||||
Object.Destroy(ref SkyLight);
|
||||
Object.Destroy(ref PostFxVolume);
|
||||
Object.Destroy(ref _editorPrimitives);
|
||||
if (_debugDrawContext != IntPtr.Zero)
|
||||
{
|
||||
DebugDraw.FreeContext(_debugDrawContext);
|
||||
_debugDrawContext = IntPtr.Zero;
|
||||
}
|
||||
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public virtual void DrawEditorPrimitives(GPUContext context, ref RenderContext renderContext, GPUTexture target, GPUTexture targetDepth)
|
||||
{
|
||||
// Draw selected objects debug shapes and visuals
|
||||
if (ShowDebugDraw && (renderContext.View.Flags & ViewFlags.DebugDraw) == ViewFlags.DebugDraw)
|
||||
{
|
||||
DebugDraw.SetContext(_debugDrawContext);
|
||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
||||
OnDebugDraw(context, ref renderContext);
|
||||
DebugDraw.Draw(ref renderContext, target.View(), targetDepth.View(), true);
|
||||
DebugDraw.SetContext(IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEditor.GUI.ContextMenu;
|
||||
using FlaxEditor.GUI.Input;
|
||||
using FlaxEngine;
|
||||
using Object = FlaxEngine.Object;
|
||||
@@ -12,7 +13,9 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// <seealso cref="AssetPreview" />
|
||||
public class ModelPreview : AssetPreview
|
||||
{
|
||||
private ContextMenuButton _showBoundsButton;
|
||||
private StaticModel _previewModel;
|
||||
private bool _showBounds;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the model asset to preview.
|
||||
@@ -28,6 +31,22 @@ namespace FlaxEditor.Viewport.Previews
|
||||
/// </summary>
|
||||
public StaticModel PreviewActor => _previewModel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show animated model bounding box debug view.
|
||||
/// </summary>
|
||||
public bool ShowBounds
|
||||
{
|
||||
get => _showBounds;
|
||||
set
|
||||
{
|
||||
_showBounds = value;
|
||||
if (value)
|
||||
ShowDebugDraw = true;
|
||||
if (_showBoundsButton != null)
|
||||
_showBoundsButton.Checked = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether scale the model to the normalized bounds.
|
||||
/// </summary>
|
||||
@@ -50,6 +69,9 @@ namespace FlaxEditor.Viewport.Previews
|
||||
|
||||
if (useWidgets)
|
||||
{
|
||||
// Show Bounds
|
||||
_showBoundsButton = ViewWidgetShowMenu.AddButton("Bounds", () => ShowBounds = !ShowBounds);
|
||||
|
||||
// Preview LOD
|
||||
{
|
||||
var previewLOD = ViewWidgetButtonMenu.AddButton("Preview LOD");
|
||||
@@ -85,6 +107,18 @@ namespace FlaxEditor.Viewport.Previews
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDebugDraw(GPUContext context, ref RenderContext renderContext)
|
||||
{
|
||||
base.OnDebugDraw(context, ref renderContext);
|
||||
|
||||
// Draw bounds
|
||||
if (_showBounds)
|
||||
{
|
||||
DebugDraw.DrawWireBox(_previewModel.Box, Color.Violet.RGBMultiplied(0.8f), 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using FlaxEditor.Content;
|
||||
using FlaxEditor.CustomEditors;
|
||||
using FlaxEditor.CustomEditors.Editors;
|
||||
@@ -13,6 +14,7 @@ using FlaxEditor.Viewport.Cameras;
|
||||
using FlaxEditor.Viewport.Previews;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
// ReSharper disable UnusedMember.Local
|
||||
// ReSharper disable UnusedMember.Global
|
||||
@@ -206,11 +208,18 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct AnimGraphDebugFlowInfo
|
||||
{
|
||||
public uint NodeId;
|
||||
public int BoxId;
|
||||
}
|
||||
|
||||
private FlaxObjectRefPickerControl _debugPicker;
|
||||
private NavigationBar _navigationBar;
|
||||
private PropertiesProxy _properties;
|
||||
private Tab _previewTab;
|
||||
private readonly List<Editor.AnimGraphDebugFlowInfo> _debugFlows = new List<Editor.AnimGraphDebugFlowInfo>();
|
||||
private readonly List<AnimGraphDebugFlowInfo> _debugFlows = new List<AnimGraphDebugFlowInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the animated model actor used for the animation preview.
|
||||
@@ -285,7 +294,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
Parent = this
|
||||
};
|
||||
|
||||
Editor.AnimGraphDebugFlow += OnDebugFlow;
|
||||
Animations.DebugFlow += OnDebugFlow;
|
||||
}
|
||||
|
||||
private void OnSurfaceContextChanged(VisjectSurfaceContext context)
|
||||
@@ -293,26 +302,27 @@ namespace FlaxEditor.Windows.Assets
|
||||
_surface.UpdateNavigationBar(_navigationBar, _toolstrip);
|
||||
}
|
||||
|
||||
private bool OnCheckValid(FlaxEngine.Object obj, ScriptType type)
|
||||
private bool OnCheckValid(Object obj, ScriptType type)
|
||||
{
|
||||
return obj is AnimatedModel player && player.AnimationGraph == OriginalAsset;
|
||||
}
|
||||
|
||||
private void OnDebugFlow(Editor.AnimGraphDebugFlowInfo flowInfo)
|
||||
private void OnDebugFlow(Asset asset, Object obj, uint nodeId, uint boxId)
|
||||
{
|
||||
// Filter the flow
|
||||
if (_debugPicker.Value != null)
|
||||
{
|
||||
if (flowInfo.Asset != OriginalAsset || _debugPicker.Value != flowInfo.Object)
|
||||
if (asset != OriginalAsset || _debugPicker.Value != obj)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flowInfo.Asset != Asset || _preview.PreviewActor != flowInfo.Object)
|
||||
if (asset != Asset || _preview.PreviewActor != obj)
|
||||
return;
|
||||
}
|
||||
|
||||
// Register flow to show it in UI on a surface
|
||||
var flowInfo = new AnimGraphDebugFlowInfo { NodeId = nodeId, BoxId = (int)boxId };
|
||||
lock (_debugFlows)
|
||||
{
|
||||
_debugFlows.Add(flowInfo);
|
||||
@@ -457,7 +467,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
Editor.AnimGraphDebugFlow -= OnDebugFlow;
|
||||
Animations.DebugFlow -= OnDebugFlow;
|
||||
|
||||
_properties = null;
|
||||
_navigationBar = null;
|
||||
|
||||
@@ -135,7 +135,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
/// <inheritdoc />
|
||||
protected override void UnlinkItem()
|
||||
{
|
||||
_textPreview.Font = new FontReference();
|
||||
_textPreview.Font = null;
|
||||
|
||||
base.UnlinkItem();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace FlaxEditor.Windows.Assets
|
||||
var newRoot = Object.Find<Actor>(ref newRootId);
|
||||
|
||||
_window.Graph.MainActor = null;
|
||||
_window.Viewport.Instance = null;
|
||||
|
||||
if (SceneGraphFactory.Nodes.TryGetValue(oldRootId, out var oldRootNode))
|
||||
oldRootNode.Dispose();
|
||||
if (SceneGraphFactory.Nodes.TryGetValue(newRootId, out var newRootNode))
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user