Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c328d2b559 | |||
| 65747c9ddf | |||
| d4a4ae996e | |||
| e312485a34 | |||
| 7dfe709196 | |||
| 759845c37b | |||
| 5e3fe56aa7 | |||
| 4b506560e9 | |||
| 330c46b949 | |||
| b29d1f9902 | |||
| 15f60b33b1 | |||
| 1a54ea82b5 | |||
| 949bc67354 | |||
| d816af41b4 | |||
| a7880d73f3 | |||
| ac21c4d1e7 | |||
| ed8a10f276 | |||
| 8b8a83eb20 | |||
| 890ea38470 | |||
| 07d06c74b5 | |||
| ec18b01ef7 | |||
| 7a1817b099 | |||
| a2782515a2 | |||
| 9deb021a5e | |||
| 0bbb72e24d | |||
| 7656cf541d | |||
| d77ad33583 | |||
| 6f5605b7ca | |||
| 718ae78036 | |||
| f6eef82864 | |||
| 26d37103ba | |||
| d85c65bfc5 | |||
| 1943c64a33 | |||
| 9c1fa7c0ce | |||
| 14068307d1 | |||
| 670e48ec1c | |||
| e288104472 | |||
| 99b0cf71a8 | |||
| 2b7e6944e8 | |||
| 9e7ce69e9c | |||
| 8c97a645e9 | |||
| d194a06e59 | |||
| 783372c787 | |||
| 51016949b8 | |||
| 128cad49b9 | |||
| 65f9e9d0aa | |||
| 36df9757b1 | |||
| a0e1c7c37e | |||
| 847641f655 | |||
| cdca5b4a28 | |||
| 6609425880 | |||
| 6ac0d5d3f4 | |||
| bc46259286 | |||
| 50bccd52e7 | |||
| 84cca1ae98 | |||
| 71cf758ccf | |||
| edf98acae2 | |||
| a085531fda | |||
| 6b532d2fbc | |||
| 7862ff4670 | |||
| bc27890818 | |||
| 1c5754beff | |||
| 054def3d13 | |||
| e6d5d5330e | |||
| f430803ecc | |||
| fc762fdbdb | |||
| 6908aa4a8a | |||
| 6c70f2e14f | |||
| 3bc489a7b5 | |||
| d22380c7cf | |||
| c4102ba884 | |||
| baee3a60a6 | |||
| 5e2b4adff3 | |||
| 78d668c599 | |||
| e8b867430f | |||
| 1426b4ca49 | |||
| 9682ac4643 | |||
| d95cd24b76 |
@@ -194,16 +194,16 @@ void PS_Decal(
|
|||||||
Out2 = float4(material.Emissive, material.Opacity);
|
Out2 = float4(material.Emissive, material.Opacity);
|
||||||
#if USE_NORMAL
|
#if USE_NORMAL
|
||||||
// GBuffer1
|
// GBuffer1
|
||||||
Out3 = float4(material.WorldNormal * 0.5f + 0.5f, 1);
|
Out3 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
||||||
#endif
|
#endif
|
||||||
#elif USE_NORMAL
|
#elif USE_NORMAL
|
||||||
// GBuffer1
|
// GBuffer1
|
||||||
Out2 = float4(material.WorldNormal * 0.5f + 0.5f, 1);
|
Out2 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
||||||
#endif
|
#endif
|
||||||
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_STAIN
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_STAIN
|
||||||
Out0 = float4(material.Color, material.Opacity);
|
Out0 = float4(material.Color, material.Opacity);
|
||||||
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_NORMAL
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_NORMAL
|
||||||
Out0 = float4(material.WorldNormal * 0.5f + 0.5f, 1);
|
Out0 = float4(material.WorldNormal * 0.5f + 0.5f, material.Opacity);
|
||||||
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_EMISSIVE
|
#elif DECAL_BLEND_MODE == DECAL_BLEND_MODE_EMISSIVE
|
||||||
Out0 = float4(material.Emissive * material.Opacity, material.Opacity);
|
Out0 = float4(material.Emissive * material.Opacity, material.Opacity);
|
||||||
#else
|
#else
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
"Version": {
|
"Version": {
|
||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 2,
|
"Minor": 2,
|
||||||
"Build": 6222
|
"Build": 6224
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",
|
"Copyright": "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.",
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
|
|
||||||
void RegisterGameCookingStart(GameCooker::EventType type)
|
void RegisterGameCookingStart(GameCooker::EventType type)
|
||||||
{
|
{
|
||||||
auto platform = ToString(GameCooker::GetCurrentData().Platform);
|
auto& data = *GameCooker::GetCurrentData();
|
||||||
|
auto platform = ToString(data.Platform);
|
||||||
if (type == GameCooker::EventType::BuildStarted)
|
if (type == GameCooker::EventType::BuildStarted)
|
||||||
{
|
{
|
||||||
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
EditorAnalytics::SendEvent("Actions", "GameCooker.Start", platform);
|
||||||
|
|||||||
@@ -27,6 +27,22 @@ namespace FlaxEditor.Content.GUI
|
|||||||
List,
|
List,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The method sort for items.
|
||||||
|
/// </summary>
|
||||||
|
public enum SortType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The classic alphabetic sort method (A-Z).
|
||||||
|
/// </summary>
|
||||||
|
AlphabeticOrder,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The reverse alphabetic sort method (Z-A).
|
||||||
|
/// </summary>
|
||||||
|
AlphabeticReverse
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Main control for <see cref="ContentWindow"/> used to present collection of <see cref="ContentItem"/>.
|
/// Main control for <see cref="ContentWindow"/> used to present collection of <see cref="ContentItem"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -218,8 +234,9 @@ namespace FlaxEditor.Content.GUI
|
|||||||
/// Shows the items collection in the view.
|
/// Shows the items collection in the view.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="items">The items to show.</param>
|
/// <param name="items">The items to show.</param>
|
||||||
|
/// <param name="sortType">The sort method for items.</param>
|
||||||
/// <param name="additive">If set to <c>true</c> items will be added to the current selection. Otherwise selection will be cleared before.</param>
|
/// <param name="additive">If set to <c>true</c> items will be added to the current selection. Otherwise selection will be cleared before.</param>
|
||||||
public void ShowItems(List<ContentItem> items, bool additive = false)
|
public void ShowItems(List<ContentItem> items, SortType sortType, bool additive = false)
|
||||||
{
|
{
|
||||||
if (items == null)
|
if (items == null)
|
||||||
throw new ArgumentNullException();
|
throw new ArgumentNullException();
|
||||||
@@ -249,9 +266,24 @@ namespace FlaxEditor.Content.GUI
|
|||||||
items[i].AddReference(this);
|
items[i].AddReference(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort items
|
// Sort items depending on sortMethod parameter
|
||||||
_children.Sort();
|
_children.Sort(((control, control1) =>
|
||||||
|
{
|
||||||
|
if (sortType == SortType.AlphabeticReverse)
|
||||||
|
{
|
||||||
|
if (control.CompareTo(control1) > 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (control.CompareTo(control1) == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return control.CompareTo(control1);
|
||||||
|
}));
|
||||||
|
|
||||||
// Unload and perform UI layout
|
// Unload and perform UI layout
|
||||||
IsLayoutLocked = wasLayoutLocked;
|
IsLayoutLocked = wasLayoutLocked;
|
||||||
PerformLayout();
|
PerformLayout();
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Engine/Core/Log.h"
|
#include "Engine/Core/Log.h"
|
||||||
#include "Engine/Core/Enums.h"
|
#include "Engine/Core/Types/Guid.h"
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
#include "Engine/Core/Collections/HashSet.h"
|
#include "Engine/Core/Collections/HashSet.h"
|
||||||
#include "Engine/Core/Collections/Dictionary.h"
|
#include "Engine/Core/Collections/Dictionary.h"
|
||||||
#include "Engine/Core/Types/Guid.h"
|
#include "Engine/Scripting/ScriptingObject.h"
|
||||||
|
|
||||||
class GameCooker;
|
class GameCooker;
|
||||||
class PlatformTools;
|
class PlatformTools;
|
||||||
@@ -125,47 +125,60 @@ extern FLAXENGINE_API const Char* ToString(const BuildConfiguration configuratio
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Game cooking temporary data.
|
/// Game cooking temporary data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
struct FLAXENGINE_API CookingData
|
API_CLASS(Sealed, Namespace="FlaxEditor") class FLAXENGINE_API CookingData : public PersistentScriptingObject
|
||||||
{
|
{
|
||||||
|
DECLARE_SCRIPTING_TYPE(CookingData);
|
||||||
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The platform.
|
/// The platform.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BuildPlatform Platform;
|
API_FIELD(ReadOnly) BuildPlatform Platform;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The configuration.
|
/// The configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BuildConfiguration Configuration;
|
API_FIELD(ReadOnly) BuildConfiguration Configuration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The options.
|
/// The options.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
BuildOptions Options;
|
API_FIELD(ReadOnly) BuildOptions Options;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of build preset used for cooking (can be used by editor and game plugins).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(ReadOnly) String Preset;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The name of build preset target used for cooking (can be used by editor and game plugins).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(ReadOnly) String PresetTarget;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).
|
/// The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Array<String> CustomDefines;
|
API_FIELD(ReadOnly) Array<String> CustomDefines;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The original output path (actual OutputPath could be modified by the Platform Tools or a plugin for additional layout customizations or packaging). This path is preserved.
|
/// The original output path (actual OutputPath could be modified by the Platform Tools or a plugin for additional layout customizations or packaging). This path is preserved.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
String OriginalOutputPath;
|
API_FIELD(ReadOnly) String OriginalOutputPath;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The output path for data files (Content, Mono, etc.).
|
/// The output path for data files (Content, Mono, etc.).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
String DataOutputPath;
|
API_FIELD(ReadOnly) String DataOutputPath;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The output path for binaries (native executable and native code libraries).
|
/// The output path for binaries (native executable and native code libraries).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
String NativeCodeOutputPath;
|
API_FIELD(ReadOnly) String NativeCodeOutputPath;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The output path for binaries (C# code libraries).
|
/// The output path for binaries (C# code libraries).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
String ManagedCodeOutputPath;
|
API_FIELD(ReadOnly) String ManagedCodeOutputPath;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The platform tools.
|
/// The platform tools.
|
||||||
@@ -248,7 +261,7 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
HashSet<Guid> Assets;
|
HashSet<Guid> Assets;
|
||||||
|
|
||||||
struct BinaryModule
|
struct BinaryModuleInfo
|
||||||
{
|
{
|
||||||
String Name;
|
String Name;
|
||||||
String NativePath;
|
String NativePath;
|
||||||
@@ -258,17 +271,10 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The binary modules used in the build. Valid after scripts compilation step. This list includes game, all plugins modules and engine module.
|
/// The binary modules used in the build. Valid after scripts compilation step. This list includes game, all plugins modules and engine module.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Array<BinaryModule, InlinedAllocation<64>> BinaryModules;
|
Array<BinaryModuleInfo, InlinedAllocation<64>> BinaryModules;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
void Init()
|
|
||||||
{
|
|
||||||
RootAssets.Clear();
|
|
||||||
Assets.Clear();
|
|
||||||
Stats = Statistics();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the absolute path to the Platform Data folder that contains the binary files used by the current build configuration.
|
/// Gets the absolute path to the Platform Data folder that contains the binary files used by the current build configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace GameCookerImpl
|
|||||||
String ProgressMsg;
|
String ProgressMsg;
|
||||||
float ProgressValue;
|
float ProgressValue;
|
||||||
|
|
||||||
CookingData Data;
|
CookingData* Data = nullptr;
|
||||||
Array<GameCooker::BuildStep*> Steps;
|
Array<GameCooker::BuildStep*> Steps;
|
||||||
Dictionary<BuildPlatform, PlatformTools*> Tools;
|
Dictionary<BuildPlatform, PlatformTools*> Tools;
|
||||||
|
|
||||||
@@ -154,6 +154,11 @@ CookingData::Statistics::Statistics()
|
|||||||
ContentSizeMB = 0;
|
ContentSizeMB = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CookingData::CookingData(const SpawnParams& params)
|
||||||
|
: PersistentScriptingObject(params)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
String CookingData::GetGameBinariesPath() const
|
String CookingData::GetGameBinariesPath() const
|
||||||
{
|
{
|
||||||
const Char* archDir;
|
const Char* archDir;
|
||||||
@@ -179,7 +184,7 @@ String CookingData::GetGameBinariesPath() const
|
|||||||
return String::Empty;
|
return String::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPlatformBinariesRoot() / TEXT("Game") / archDir / ToString(Configuration);
|
return GetPlatformBinariesRoot() / TEXT("Game") / archDir / ::ToString(Configuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
String CookingData::GetPlatformBinariesRoot() const
|
String CookingData::GetPlatformBinariesRoot() const
|
||||||
@@ -239,7 +244,7 @@ public:
|
|||||||
|
|
||||||
GameCookerService GameCookerServiceInstance;
|
GameCookerService GameCookerServiceInstance;
|
||||||
|
|
||||||
const CookingData& GameCooker::GetCurrentData()
|
CookingData* GameCooker::GetCurrentData()
|
||||||
{
|
{
|
||||||
return Data;
|
return Data;
|
||||||
}
|
}
|
||||||
@@ -313,7 +318,7 @@ PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration, const StringView& outputPath, BuildOptions options, const Array<String>& customDefines)
|
void GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration, const StringView& outputPath, BuildOptions options, const Array<String>& customDefines, const StringView& preset, const StringView& presetTarget)
|
||||||
{
|
{
|
||||||
if (IsRunning())
|
if (IsRunning())
|
||||||
{
|
{
|
||||||
@@ -331,12 +336,14 @@ void GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
|
|||||||
CancelFlag = 0;
|
CancelFlag = 0;
|
||||||
ProgressMsg.Clear();
|
ProgressMsg.Clear();
|
||||||
ProgressValue = 1.0f;
|
ProgressValue = 1.0f;
|
||||||
CookingData& data = Data;
|
Data = New<CookingData>();
|
||||||
data.Init();
|
CookingData& data = *Data;
|
||||||
data.Tools = tools;
|
data.Tools = tools;
|
||||||
data.Platform = platform;
|
data.Platform = platform;
|
||||||
data.Configuration = configuration;
|
data.Configuration = configuration;
|
||||||
data.Options = options;
|
data.Options = options;
|
||||||
|
data.Preset = preset;
|
||||||
|
data.PresetTarget = presetTarget;
|
||||||
data.CustomDefines = customDefines;
|
data.CustomDefines = customDefines;
|
||||||
data.OriginalOutputPath = outputPath;
|
data.OriginalOutputPath = outputPath;
|
||||||
FileSystem::NormalizePath(data.OriginalOutputPath);
|
FileSystem::NormalizePath(data.OriginalOutputPath);
|
||||||
@@ -448,7 +455,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
|||||||
|
|
||||||
bool GameCookerImpl::Build()
|
bool GameCookerImpl::Build()
|
||||||
{
|
{
|
||||||
CookingData& data = Data;
|
CookingData& data = *Data;
|
||||||
LOG(Info, "Starting Game Cooker...");
|
LOG(Info, "Starting Game Cooker...");
|
||||||
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
||||||
LOG(Info, "Output Path: {0}", data.OriginalOutputPath);
|
LOG(Info, "Output Path: {0}", data.OriginalOutputPath);
|
||||||
@@ -472,7 +479,7 @@ bool GameCookerImpl::Build()
|
|||||||
CallEvent(GameCooker::EventType::BuildStarted);
|
CallEvent(GameCooker::EventType::BuildStarted);
|
||||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||||
Steps[stepIndex]->OnBuildStarted(data);
|
Steps[stepIndex]->OnBuildStarted(data);
|
||||||
Data.Tools->OnBuildStarted(data);
|
data.Tools->OnBuildStarted(data);
|
||||||
data.InitProgress(Steps.Count());
|
data.InitProgress(Steps.Count());
|
||||||
|
|
||||||
// Execute all steps in a sequence
|
// Execute all steps in a sequence
|
||||||
@@ -511,10 +518,12 @@ bool GameCookerImpl::Build()
|
|||||||
}
|
}
|
||||||
IsRunning = false;
|
IsRunning = false;
|
||||||
CancelFlag = 0;
|
CancelFlag = 0;
|
||||||
Data.Tools->OnBuildEnded(data, failed);
|
data.Tools->OnBuildEnded(data, failed);
|
||||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||||
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
CallEvent(failed ? GameCooker::EventType::BuildFailed : GameCooker::EventType::BuildDone);
|
||||||
|
Delete(Data);
|
||||||
|
Data = nullptr;
|
||||||
|
|
||||||
return failed;
|
return failed;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current build data. Valid only during active build process.
|
/// Gets the current build data. Valid only during active build process.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static const CookingData& GetCurrentData();
|
API_PROPERTY() static CookingData* GetCurrentData();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether game building is running.
|
/// Determines whether game building is running.
|
||||||
@@ -83,7 +83,9 @@ public:
|
|||||||
/// <param name="outputPath">The output path (output directory).</param>
|
/// <param name="outputPath">The output path (output directory).</param>
|
||||||
/// <param name="options">The build options.</param>
|
/// <param name="options">The build options.</param>
|
||||||
/// <param name="customDefines">The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).</param>
|
/// <param name="customDefines">The list of custom defines passed to the build tool when compiling project scripts. Can be used in build scripts for configuration (Configuration.CustomDefines).</param>
|
||||||
API_FUNCTION() static void Build(BuildPlatform platform, BuildConfiguration configuration, const StringView& outputPath, BuildOptions options, const Array<String>& customDefines);
|
/// <param name="preset">The name of build preset used for cooking (can be used by editor and game plugins).</param>
|
||||||
|
/// <param name="presetTarget">The name of build preset target used for cooking (can be used by editor and game plugins).</param>
|
||||||
|
API_FUNCTION() static void Build(BuildPlatform platform, BuildConfiguration configuration, const StringView& outputPath, BuildOptions options, const Array<String>& customDefines, const StringView& preset = StringView::Empty, const StringView& presetTarget = StringView::Empty);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends a cancel event to the game building service.
|
/// Sends a cancel event to the game building service.
|
||||||
|
|||||||
@@ -101,11 +101,6 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool IsSetBlocked => _isSetBlocked;
|
protected bool IsSetBlocked => _isSetBlocked;
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a value indicating whether this editor needs value propagation up (value synchronization when one of the child editors changes value, used by the struct types).
|
|
||||||
/// </summary>
|
|
||||||
protected virtual bool NeedsValuePropagationUp => Values.HasValueType;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The linked label used to show this custom editor. Can be null if not used (eg. editor is inlined or is using a very customized UI layout).
|
/// The linked label used to show this custom editor. Can be null if not used (eg. editor is inlined or is using a very customized UI layout).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -281,7 +276,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
|
|
||||||
// Propagate values up (eg. when member of structure gets modified, also structure should be updated as a part of the other object)
|
// Propagate values up (eg. when member of structure gets modified, also structure should be updated as a part of the other object)
|
||||||
var obj = _parent;
|
var obj = _parent;
|
||||||
while (obj._parent != null && !(obj._parent is SyncPointEditor)) // && obj.NeedsValuePropagationUp)
|
while (obj._parent != null && !(obj._parent is SyncPointEditor))
|
||||||
{
|
{
|
||||||
obj.Values.Set(obj._parent.Values, obj.Values);
|
obj.Values.Set(obj._parent.Values, obj.Values);
|
||||||
obj = obj._parent;
|
obj = obj._parent;
|
||||||
@@ -301,12 +296,15 @@ namespace FlaxEditor.CustomEditors
|
|||||||
_isSetBlocked = false;
|
_isSetBlocked = false;
|
||||||
|
|
||||||
// Update children
|
// Update children
|
||||||
|
if (_skipChildrenRefresh)
|
||||||
|
{
|
||||||
|
_skipChildrenRefresh = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var childrenCount = _skipChildrenRefresh ? 0 : _children.Count;
|
for (int i = 0; i < _children.Count; i++)
|
||||||
for (int i = 0; i < childrenCount; i++)
|
|
||||||
_children[i].RefreshInternal();
|
_children[i].RefreshInternal();
|
||||||
_skipChildrenRefresh = false;
|
|
||||||
}
|
}
|
||||||
catch (TargetException ex)
|
catch (TargetException ex)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -154,6 +154,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
var panel = layout.VerticalPanel();
|
var panel = layout.VerticalPanel();
|
||||||
panel.Panel.BackgroundColor = _background;
|
panel.Panel.BackgroundColor = _background;
|
||||||
var elementType = ElementType;
|
var elementType = ElementType;
|
||||||
|
|
||||||
|
// Use separate layout cells for each collection items to improve layout updates for them in separation
|
||||||
|
var useSharedLayout = elementType.IsPrimitive || elementType.IsEnum;
|
||||||
|
|
||||||
if (_canReorderItems)
|
if (_canReorderItems)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
@@ -178,7 +182,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
|
|
||||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||||
panel.Object(new CollectionItemLabel(this, i), new ListValueContainer(elementType, i, Values), overrideEditor);
|
var property = panel.AddPropertyItem(new CollectionItemLabel(this, i));
|
||||||
|
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
|
||||||
|
itemLayout.Object(new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -194,7 +200,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
|
|
||||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||||
panel.Object("Element " + i, new ListValueContainer(elementType, i, Values), overrideEditor);
|
var property = panel.AddPropertyItem("Element " + i);
|
||||||
|
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
|
||||||
|
itemLayout.Object(new ListValueContainer(elementType, i, Values), overrideEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -216,6 +216,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
panel.Panel.BackgroundColor = _background;
|
panel.Panel.BackgroundColor = _background;
|
||||||
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
|
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
|
||||||
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
|
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
|
||||||
|
var valuesType = new ScriptType(valueType);
|
||||||
|
|
||||||
|
// Use separate layout cells for each collection items to improve layout updates for them in separation
|
||||||
|
var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum;
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i < size; i++)
|
||||||
{
|
{
|
||||||
if (i != 0 && spacing > 0f)
|
if (i != 0 && spacing > 0f)
|
||||||
@@ -239,7 +244,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
|
|
||||||
var key = keys.ElementAt(i);
|
var key = keys.ElementAt(i);
|
||||||
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
var overrideEditor = overrideEditorType != null ? (CustomEditor)Activator.CreateInstance(overrideEditorType) : null;
|
||||||
panel.Object(new DictionaryItemLabel(this, key), new DictionaryValueContainer(new ScriptType(valueType), key, Values), overrideEditor);
|
var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key));
|
||||||
|
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
|
||||||
|
itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_elementsCount = size;
|
_elementsCount = size;
|
||||||
|
|||||||
@@ -96,14 +96,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
// Update tooltip
|
// Update tooltip
|
||||||
if (_value is SceneObject sceneObject)
|
if (_value is SceneObject sceneObject)
|
||||||
{
|
{
|
||||||
var str = sceneObject is Actor actor ? actor.Name : type.Name;
|
TooltipText = Utilities.Utils.GetTooltip(sceneObject);
|
||||||
var o = sceneObject.Parent;
|
|
||||||
while (o)
|
|
||||||
{
|
|
||||||
str = o.Name + " -> " + str;
|
|
||||||
o = o.Parent;
|
|
||||||
}
|
|
||||||
TooltipText = str;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
|
|
||||||
private VisibleIfCache[] _visibleIfCaches;
|
private VisibleIfCache[] _visibleIfCaches;
|
||||||
|
private bool _isNull;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the items for the type
|
/// Gets the items for the type
|
||||||
@@ -264,7 +265,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
// Skip properties without getter or setter
|
// Skip properties without getter or setter
|
||||||
if (!p.HasGet || (!p.HasSet && !showInEditor))
|
if (!p.HasGet || (!p.HasSet && !showInEditor))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Skip hidden fields, handle special attributes
|
// Skip hidden fields, handle special attributes
|
||||||
if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute))
|
if ((!p.IsPublic && !showInEditor) || attributes.Any(x => x is HideInEditorAttribute))
|
||||||
continue;
|
continue;
|
||||||
@@ -418,6 +419,14 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
internal override void Initialize(CustomEditorPresenter presenter, LayoutElementsContainer layout, ValueContainer values)
|
||||||
|
{
|
||||||
|
_isNull = values != null && values.IsNull;
|
||||||
|
|
||||||
|
base.Initialize(presenter, layout, values);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Initialize(LayoutElementsContainer layout)
|
public override void Initialize(LayoutElementsContainer layout)
|
||||||
{
|
{
|
||||||
@@ -446,12 +455,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
Parent = layout.ContainerControl,
|
Parent = layout.ContainerControl,
|
||||||
Location = new Vector2(layout.ContainerControl.Width - ButtonSize - 4, (layout.ContainerControl.Height - ButtonSize) * 0.5f),
|
Location = new Vector2(layout.ContainerControl.Width - ButtonSize - 4, (layout.ContainerControl.Height - ButtonSize) * 0.5f),
|
||||||
};
|
};
|
||||||
button.Clicked += () =>
|
button.Clicked += () => SetValue(Values.Type.CreateInstance());
|
||||||
{
|
|
||||||
var newType = Values.Type;
|
|
||||||
SetValue(newType.CreateInstance());
|
|
||||||
RebuildLayoutOnRefresh();
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layout.Label("<null>");
|
layout.Label("<null>");
|
||||||
@@ -558,6 +562,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Refresh()
|
public override void Refresh()
|
||||||
{
|
{
|
||||||
|
// Automatic refresh when value nullability changed
|
||||||
|
if (_isNull != Values.IsNull)
|
||||||
|
{
|
||||||
|
RebuildLayout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_visibleIfCaches != null)
|
if (_visibleIfCaches != null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
@@ -76,14 +76,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
|||||||
if (_value)
|
if (_value)
|
||||||
{
|
{
|
||||||
_valueName = _value.Name;
|
_valueName = _value.Name;
|
||||||
TooltipText = _value.TypeName;
|
TooltipText = Surface.SurfaceUtils.GetVisualScriptTypeDescription(_value);
|
||||||
|
|
||||||
var attributes = _value.GetAttributes(false);
|
|
||||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
|
||||||
if (tooltipAttribute != null)
|
|
||||||
{
|
|
||||||
TooltipText += "\n" + tooltipAttribute.Text;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,6 +30,11 @@ namespace FlaxEditor.CustomEditors
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly List<LayoutElement> Children = new List<LayoutElement>();
|
public readonly List<LayoutElement> Children = new List<LayoutElement>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The child custom editors.
|
||||||
|
/// </summary>
|
||||||
|
public readonly List<CustomEditor> Editors = new List<CustomEditor>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the control represented by this element.
|
/// Gets the control represented by this element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -722,6 +727,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
var customEditor = CustomEditor.CurrentCustomEditor;
|
var customEditor = CustomEditor.CurrentCustomEditor;
|
||||||
Assert.IsNotNull(customEditor);
|
Assert.IsNotNull(customEditor);
|
||||||
customEditor.OnChildCreated(editor);
|
customEditor.OnChildCreated(editor);
|
||||||
|
Editors.Add(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -730,6 +736,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
public virtual void ClearLayout()
|
public virtual void ClearLayout()
|
||||||
{
|
{
|
||||||
Children.Clear();
|
Children.Clear();
|
||||||
|
Editors.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -101,6 +101,22 @@ namespace FlaxEditor.CustomEditors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether all values in the collection are null. Returns true if collection is empty.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNull
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i] != null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this any value in the collection is of value type (eg. a structure, not a class type). Returns false if collection is empty.
|
/// Gets a value indicating whether this any value in the collection is of value type (eg. a structure, not a class type). Returns false if collection is empty.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -388,6 +388,105 @@ int32 Editor::LoadProduct()
|
|||||||
projectPath.Clear();
|
projectPath.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create new project option
|
||||||
|
if (CommandLine::Options.NewProject)
|
||||||
|
{
|
||||||
|
if (projectPath.IsEmpty())
|
||||||
|
projectPath = Platform::GetWorkingDirectory();
|
||||||
|
else if (!FileSystem::DirectoryExists(projectPath))
|
||||||
|
FileSystem::CreateDirectory(projectPath);
|
||||||
|
FileSystem::NormalizePath(projectPath);
|
||||||
|
|
||||||
|
String folderName = StringUtils::GetFileName(projectPath);
|
||||||
|
String tmpName;
|
||||||
|
for (int32 i = 0; i < folderName.Length(); i++)
|
||||||
|
{
|
||||||
|
Char c = folderName[i];
|
||||||
|
if (StringUtils::IsAlnum(c) && c != ' ' && c != '.')
|
||||||
|
tmpName += c;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create project file
|
||||||
|
ProjectInfo newProject;
|
||||||
|
newProject.Name = MoveTemp(tmpName);
|
||||||
|
newProject.ProjectPath = projectPath / newProject.Name + TEXT(".flaxproj");
|
||||||
|
newProject.ProjectFolderPath = projectPath;
|
||||||
|
newProject.Version = Version(1, 0);
|
||||||
|
newProject.Company = TEXT("My Company");
|
||||||
|
newProject.MinEngineVersion = FLAXENGINE_VERSION;
|
||||||
|
newProject.GameTarget = TEXT("GameTarget");
|
||||||
|
newProject.EditorTarget = TEXT("GameEditorTarget");
|
||||||
|
auto& flaxRef = newProject.References.AddOne();
|
||||||
|
flaxRef.Name = TEXT("$(EnginePath)/Flax.flaxproj");
|
||||||
|
flaxRef.Project = nullptr;
|
||||||
|
if (newProject.SaveProject())
|
||||||
|
return 10;
|
||||||
|
|
||||||
|
// Generate source files
|
||||||
|
if (FileSystem::CreateDirectory(projectPath / TEXT("Content")))
|
||||||
|
return 11;
|
||||||
|
if (FileSystem::CreateDirectory(projectPath / TEXT("Source/Game")))
|
||||||
|
return 11;
|
||||||
|
bool failed = File::WriteAllText(projectPath / TEXT("Source/GameTarget.Build.cs"),TEXT(
|
||||||
|
"using Flax.Build;\n"
|
||||||
|
"\n"
|
||||||
|
"public class GameTarget : GameProjectTarget\n"
|
||||||
|
"{\n"
|
||||||
|
" /// <inheritdoc />\n"
|
||||||
|
" public override void Init()\n"
|
||||||
|
" {\n"
|
||||||
|
" base.Init();\n"
|
||||||
|
"\n"
|
||||||
|
" // Reference the modules for game\n"
|
||||||
|
" Modules.Add(\"Game\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"), Encoding::Unicode);
|
||||||
|
failed |= File::WriteAllText(projectPath / TEXT("Source/GameEditorTarget.Build.cs"),TEXT(
|
||||||
|
"using Flax.Build;\n"
|
||||||
|
"\n"
|
||||||
|
"public class GameEditorTarget : GameProjectEditorTarget\n"
|
||||||
|
"{\n"
|
||||||
|
" /// <inheritdoc />\n"
|
||||||
|
" public override void Init()\n"
|
||||||
|
" {\n"
|
||||||
|
" base.Init();\n"
|
||||||
|
"\n"
|
||||||
|
" // Reference the modules for editor\n"
|
||||||
|
" Modules.Add(\"Game\");\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"), Encoding::Unicode);
|
||||||
|
failed |= File::WriteAllText(projectPath / TEXT("Source/Game/Game.Build.cs"),TEXT(
|
||||||
|
"using Flax.Build;\n"
|
||||||
|
"using Flax.Build.NativeCpp;\n"
|
||||||
|
"\n"
|
||||||
|
"public class Game : GameModule\n"
|
||||||
|
"{\n"
|
||||||
|
" /// <inheritdoc />\n"
|
||||||
|
" public override void Init()\n"
|
||||||
|
" {\n"
|
||||||
|
" base.Init();\n"
|
||||||
|
"\n"
|
||||||
|
" // C#-only scripting\n"
|
||||||
|
" BuildNativeCode = false;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" /// <inheritdoc />\n"
|
||||||
|
" public override void Setup(BuildOptions options)\n"
|
||||||
|
" {\n"
|
||||||
|
" base.Setup(options);\n"
|
||||||
|
"\n"
|
||||||
|
" options.ScriptingAPI.IgnoreMissingDocumentationWarnings = true;\n"
|
||||||
|
"\n"
|
||||||
|
" // Here you can modify the build options for your game module\n"
|
||||||
|
" // To reference another module use: options.PublicDependencies.Add(\"Audio\");\n"
|
||||||
|
" // To add C++ define use: options.PublicDefinitions.Add(\"COMPILE_WITH_FLAX\");\n"
|
||||||
|
" // To learn more see scripting documentation.\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"), Encoding::Unicode);
|
||||||
|
if (failed)
|
||||||
|
return 12;
|
||||||
|
}
|
||||||
|
|
||||||
// Missing project case
|
// Missing project case
|
||||||
if (projectPath.IsEmpty())
|
if (projectPath.IsEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
+31
-2
@@ -272,8 +272,10 @@ namespace FlaxEditor
|
|||||||
module.OnEndInit();
|
module.OnEndInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Init(bool isHeadless, bool skipCompile, Guid startupScene)
|
internal void Init(bool isHeadless, bool skipCompile, bool newProject, Guid startupScene)
|
||||||
{
|
{
|
||||||
|
if (newProject)
|
||||||
|
InitProject();
|
||||||
EnsureState<LoadingState>();
|
EnsureState<LoadingState>();
|
||||||
_isHeadlessMode = isHeadless;
|
_isHeadlessMode = isHeadless;
|
||||||
_startupSceneCmdLine = startupScene;
|
_startupSceneCmdLine = startupScene;
|
||||||
@@ -473,6 +475,33 @@ namespace FlaxEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitProject()
|
||||||
|
{
|
||||||
|
// Initialize empty project with default game configuration
|
||||||
|
Log("Initialize new project");
|
||||||
|
var project = GameProject;
|
||||||
|
var gameSettings = new GameSettings
|
||||||
|
{
|
||||||
|
ProductName = project.Name,
|
||||||
|
CompanyName = project.Company,
|
||||||
|
};
|
||||||
|
GameSettings.Save(gameSettings);
|
||||||
|
GameSettings.Save(new TimeSettings());
|
||||||
|
GameSettings.Save(new AudioSettings());
|
||||||
|
GameSettings.Save(new PhysicsSettings());
|
||||||
|
GameSettings.Save(new LayersAndTagsSettings());
|
||||||
|
GameSettings.Save(new InputSettings());
|
||||||
|
GameSettings.Save(new GraphicsSettings());
|
||||||
|
GameSettings.Save(new NavigationSettings());
|
||||||
|
GameSettings.Save(new LocalizationSettings());
|
||||||
|
GameSettings.Save(new BuildSettings());
|
||||||
|
GameSettings.Save(new StreamingSettings());
|
||||||
|
GameSettings.Save(new WindowsPlatformSettings());
|
||||||
|
GameSettings.Save(new LinuxPlatformSettings());
|
||||||
|
GameSettings.Save(new AndroidPlatformSettings());
|
||||||
|
GameSettings.Save(new UWPPlatformSettings());
|
||||||
|
}
|
||||||
|
|
||||||
internal void OnPlayBeginning()
|
internal void OnPlayBeginning()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _modules.Count; i++)
|
for (int i = 0; i < _modules.Count; i++)
|
||||||
@@ -1189,7 +1218,7 @@ namespace FlaxEditor
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows.GameCookerWin.Build(target);
|
Windows.GameCookerWin.Build(preset, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
Windows.GameCookerWin.ExitOnBuildQueueEnd();
|
Windows.GameCookerWin.ExitOnBuildQueueEnd();
|
||||||
|
|||||||
@@ -456,18 +456,30 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
if (base.OnKeyDown(key))
|
if (base.OnKeyDown(key))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Se;ect the first item
|
switch (key)
|
||||||
if (key == KeyboardKeys.ArrowDown)
|
|
||||||
{
|
{
|
||||||
|
case KeyboardKeys.ArrowDown:
|
||||||
for (int i = 0; i < _panel.Children.Count; i++)
|
for (int i = 0; i < _panel.Children.Count; i++)
|
||||||
{
|
{
|
||||||
if (_panel.Children[i] is ContextMenuButton item && item.Visible)
|
if (_panel.Children[i] is ContextMenuButton item && item.Visible && item.Enabled)
|
||||||
{
|
{
|
||||||
item.Focus();
|
item.Focus();
|
||||||
_panel.ScrollViewTo(item);
|
_panel.ScrollViewTo(item);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case KeyboardKeys.ArrowUp:
|
||||||
|
for (int i = _panel.Children.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (_panel.Children[i] is ContextMenuButton item && item.Visible && item.Enabled)
|
||||||
|
{
|
||||||
|
item.Focus();
|
||||||
|
_panel.ScrollViewTo(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
case KeyboardKeys.ArrowUp:
|
case KeyboardKeys.ArrowUp:
|
||||||
for (int i = IndexInParent - 1; i >= 0; i--)
|
for (int i = IndexInParent - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
if (ParentContextMenu.ItemsContainer.Children[i] is ContextMenuButton item && item.Visible)
|
if (ParentContextMenu.ItemsContainer.Children[i] is ContextMenuButton item && item.Visible && item.Enabled)
|
||||||
{
|
{
|
||||||
item.Focus();
|
item.Focus();
|
||||||
ParentContextMenu.ItemsContainer.ScrollViewTo(item);
|
ParentContextMenu.ItemsContainer.ScrollViewTo(item);
|
||||||
@@ -194,7 +194,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
|||||||
case KeyboardKeys.ArrowDown:
|
case KeyboardKeys.ArrowDown:
|
||||||
for (int i = IndexInParent + 1; i < ParentContextMenu.ItemsContainer.Children.Count; i++)
|
for (int i = IndexInParent + 1; i < ParentContextMenu.ItemsContainer.Children.Count; i++)
|
||||||
{
|
{
|
||||||
if (ParentContextMenu.ItemsContainer.Children[i] is ContextMenuButton item && item.Visible)
|
if (ParentContextMenu.ItemsContainer.Children[i] is ContextMenuButton item && item.Visible && item.Enabled)
|
||||||
{
|
{
|
||||||
item.Focus();
|
item.Focus();
|
||||||
ParentContextMenu.ItemsContainer.ScrollViewTo(item);
|
ParentContextMenu.ItemsContainer.ScrollViewTo(item);
|
||||||
|
|||||||
@@ -74,23 +74,21 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup time axis ticks
|
// Setup time axis ticks
|
||||||
int minDistanceBetweenTicks = 4000;
|
var minDistanceBetweenTicks = 50.0f;
|
||||||
int maxDistanceBetweenTicks = 6000;
|
var maxDistanceBetweenTicks = 100.0f;
|
||||||
var zoom = Timeline.UnitsPerSecond * _timeline.Zoom;
|
var zoom = Timeline.UnitsPerSecond * _timeline.Zoom;
|
||||||
var left = Vector2.Min(leftSideMin, rightSideMax).X;
|
var left = Vector2.Min(leftSideMin, rightSideMax).X;
|
||||||
var right = Vector2.Max(leftSideMin, rightSideMax).X;
|
var right = Vector2.Max(leftSideMin, rightSideMax).X;
|
||||||
var pixelRange = (right - left) * zoom;
|
|
||||||
var leftFrame = Mathf.Floor((left - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond;
|
var leftFrame = Mathf.Floor((left - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond;
|
||||||
var rightFrame = Mathf.Ceil((right - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond;
|
var rightFrame = Mathf.Ceil((right - Timeline.StartOffset) / zoom) * _timeline.FramesPerSecond;
|
||||||
var min = leftFrame;
|
var min = leftFrame;
|
||||||
var max = rightFrame;
|
var max = rightFrame;
|
||||||
var range = max - min;
|
|
||||||
int smallestTick = 0;
|
int smallestTick = 0;
|
||||||
int biggestTick = _tickSteps.Length - 1;
|
int biggestTick = _tickSteps.Length - 1;
|
||||||
for (int i = _tickSteps.Length - 1; i >= 0; i--)
|
for (int i = _tickSteps.Length - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
// Calculate how far apart these modulo tick steps are spaced
|
// Calculate how far apart these modulo tick steps are spaced
|
||||||
float tickSpacing = _tickSteps[i] * pixelRange / range;
|
float tickSpacing = _tickSteps[i] * _timeline.Zoom;
|
||||||
|
|
||||||
// Calculate the strength of the tick markers based on the spacing
|
// Calculate the strength of the tick markers based on the spacing
|
||||||
_tickStrengths[i] = Mathf.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks));
|
_tickStrengths[i] = Mathf.Saturate((tickSpacing - minDistanceBetweenTicks) / (maxDistanceBetweenTicks - minDistanceBetweenTicks));
|
||||||
@@ -117,14 +115,16 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
|
|
||||||
// Draw all ticks
|
// Draw all ticks
|
||||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1);
|
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1);
|
||||||
int startTick = Mathf.FloorToInt(min / _tickSteps[l]);
|
var lStep = _tickSteps[l];
|
||||||
int endTick = Mathf.CeilToInt(max / _tickSteps[l]);
|
var lNextStep = _tickSteps[l + 1];
|
||||||
|
int startTick = Mathf.FloorToInt(min / lStep);
|
||||||
|
int endTick = Mathf.CeilToInt(max / lStep);
|
||||||
Color lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
|
Color lineColor = style.ForegroundDisabled.RGBMultiplied(0.7f).AlphaMultiplied(strength);
|
||||||
for (int i = startTick; i <= endTick; i++)
|
for (int i = startTick; i <= endTick; i++)
|
||||||
{
|
{
|
||||||
if (l < biggestTick && (i % Mathf.RoundToInt(_tickSteps[l + 1] / _tickSteps[l]) == 0))
|
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
|
||||||
continue;
|
continue;
|
||||||
var tick = i * _tickSteps[l];
|
var tick = i * lStep;
|
||||||
var time = tick / _timeline.FramesPerSecond;
|
var time = tick / _timeline.FramesPerSecond;
|
||||||
var x = time * zoom + Timeline.StartOffset;
|
var x = time * zoom + Timeline.StartOffset;
|
||||||
|
|
||||||
@@ -163,15 +163,17 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
|
|
||||||
// Draw all ticks
|
// Draw all ticks
|
||||||
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1);
|
int l = Mathf.Clamp(smallestTick + level, 0, _tickSteps.Length - 1);
|
||||||
int startTick = Mathf.FloorToInt(min / _tickSteps[l]);
|
var lStep = _tickSteps[l];
|
||||||
int endTick = Mathf.CeilToInt(max / _tickSteps[l]);
|
var lNextStep = _tickSteps[l + 1];
|
||||||
|
int startTick = Mathf.FloorToInt(min / lStep);
|
||||||
|
int endTick = Mathf.CeilToInt(max / lStep);
|
||||||
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
|
Color lineColor = style.Foreground.RGBMultiplied(0.8f).AlphaMultiplied(strength);
|
||||||
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
|
Color labelColor = style.ForegroundDisabled.AlphaMultiplied(strength);
|
||||||
for (int i = startTick; i <= endTick; i++)
|
for (int i = startTick; i <= endTick; i++)
|
||||||
{
|
{
|
||||||
if (l < biggestTick && (i % Mathf.RoundToInt(_tickSteps[l + 1] / _tickSteps[l]) == 0))
|
if (l < biggestTick && (i % Mathf.RoundToInt(lNextStep / lStep) == 0))
|
||||||
continue;
|
continue;
|
||||||
var tick = i * _tickSteps[l];
|
var tick = i * lStep;
|
||||||
var time = tick / _timeline.FramesPerSecond;
|
var time = tick / _timeline.FramesPerSecond;
|
||||||
var x = time * zoom + Timeline.StartOffset;
|
var x = time * zoom + Timeline.StartOffset;
|
||||||
|
|
||||||
@@ -195,17 +197,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
default: throw new ArgumentOutOfRangeException();
|
default: throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
var labelRect = new Rectangle(x + 2, -verticalLinesHeaderExtend + timeAxisHeaderOffset, 50, verticalLinesHeaderExtend);
|
var labelRect = new Rectangle(x + 2, -verticalLinesHeaderExtend + timeAxisHeaderOffset, 50, verticalLinesHeaderExtend);
|
||||||
Render2D.DrawText(
|
Render2D.DrawText(style.FontSmall, labelText, labelRect, labelColor, TextAlignment.Near, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, 0.8f);
|
||||||
style.FontSmall,
|
|
||||||
labelText,
|
|
||||||
labelRect,
|
|
||||||
labelColor,
|
|
||||||
TextAlignment.Near,
|
|
||||||
TextAlignment.Center,
|
|
||||||
TextWrapping.NoWrap,
|
|
||||||
1.0f,
|
|
||||||
0.8f
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using FlaxEngine;
|
||||||
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
|
namespace FlaxEditor.GUI.Timeline.GUI
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The timeline background area control.
|
||||||
|
/// </summary>
|
||||||
|
class BackgroundArea : Panel
|
||||||
|
{
|
||||||
|
private Timeline _timeline;
|
||||||
|
internal bool _rightMouseButtonDown;
|
||||||
|
private Vector2 _rightMouseButtonLastPos;
|
||||||
|
private float _rightMouseButtonMovement;
|
||||||
|
|
||||||
|
public BackgroundArea(Timeline timeline)
|
||||||
|
: base(ScrollBars.Both)
|
||||||
|
{
|
||||||
|
_timeline = timeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool OnMouseDown(Vector2 location, MouseButton button)
|
||||||
|
{
|
||||||
|
if (base.OnMouseDown(location, button))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (button == MouseButton.Right)
|
||||||
|
{
|
||||||
|
_rightMouseButtonDown = true;
|
||||||
|
_rightMouseButtonLastPos = location;
|
||||||
|
_rightMouseButtonMovement = 0;
|
||||||
|
Focus();
|
||||||
|
StartMouseCapture();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnMouseMove(Vector2 location)
|
||||||
|
{
|
||||||
|
// Panning timeline view with a right-mouse button
|
||||||
|
if (_rightMouseButtonDown)
|
||||||
|
{
|
||||||
|
var movePos = location + ViewOffset;
|
||||||
|
var delta = _rightMouseButtonLastPos - movePos;
|
||||||
|
_rightMouseButtonLastPos = movePos;
|
||||||
|
_rightMouseButtonMovement += delta.Length;
|
||||||
|
|
||||||
|
var hScroll = HScrollBar.Visible && HScrollBar.Enabled;
|
||||||
|
var vScroll = VScrollBar.Visible && VScrollBar.Enabled;
|
||||||
|
if (vScroll && hScroll)
|
||||||
|
Cursor = CursorType.SizeAll;
|
||||||
|
else if (vScroll)
|
||||||
|
Cursor = CursorType.SizeNS;
|
||||||
|
else if (hScroll)
|
||||||
|
Cursor = CursorType.SizeWE;
|
||||||
|
|
||||||
|
bool wasLocked = IsLayoutLocked;
|
||||||
|
IsLayoutLocked = true;
|
||||||
|
if (hScroll)
|
||||||
|
HScrollBar.TargetValue += delta.X;
|
||||||
|
if (vScroll)
|
||||||
|
VScrollBar.TargetValue += delta.Y;
|
||||||
|
IsLayoutLocked = wasLocked;
|
||||||
|
PerformLayout();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnMouseMove(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool OnMouseUp(Vector2 location, MouseButton button)
|
||||||
|
{
|
||||||
|
if (button == MouseButton.Right && _rightMouseButtonDown)
|
||||||
|
{
|
||||||
|
EndMouseCapture();
|
||||||
|
_rightMouseButtonDown = false;
|
||||||
|
Cursor = CursorType.Default;
|
||||||
|
if (_rightMouseButtonMovement < 1.0f)
|
||||||
|
{
|
||||||
|
_timeline.ShowContextMenu(PointToParent(_timeline, location));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.OnMouseUp(location, button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -27,7 +27,8 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var icon = Editor.Instance.Icons.VisjectArrowClosed32;
|
var icon = Editor.Instance.Icons.VisjectArrowClosed32;
|
||||||
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y;
|
var timeAxisOverlap = Timeline.HeaderTopAreaHeight * 0.5f;
|
||||||
|
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y - timeAxisOverlap;
|
||||||
|
|
||||||
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
|
Matrix3x3.RotationZ(Mathf.PiOverTwo, out var m1);
|
||||||
var m2 = Matrix3x3.Translation2D(0, timeAxisHeaderOffset);
|
var m2 = Matrix3x3.Translation2D(0, timeAxisHeaderOffset);
|
||||||
@@ -36,7 +37,7 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
Render2D.DrawSprite(icon, new Rectangle(new Vector2(4, -Width), Size), _timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground);
|
Render2D.DrawSprite(icon, new Rectangle(new Vector2(4, -Width), Size), _timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground);
|
||||||
Render2D.PopTransform();
|
Render2D.PopTransform();
|
||||||
|
|
||||||
Render2D.FillRectangle(new Rectangle(Width * 0.5f, Height + timeAxisHeaderOffset, 1, _timeline.MediaPanel.Height - timeAxisHeaderOffset), _timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground.RGBMultiplied(0.8f));
|
Render2D.FillRectangle(new Rectangle(Width * 0.5f, Height + timeAxisHeaderOffset, 1, _timeline.MediaPanel.Height - timeAxisHeaderOffset - timeAxisOverlap), _timeline.IsMovingPositionHandle ? style.ProgressNormal : style.Foreground.RGBMultiplied(0.8f));
|
||||||
|
|
||||||
base.Draw();
|
base.Draw();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ namespace FlaxEditor.GUI.Timeline.GUI
|
|||||||
public override void Draw()
|
public override void Draw()
|
||||||
{
|
{
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y;
|
var timeAxisOverlap = Timeline.HeaderTopAreaHeight * 0.5f;
|
||||||
|
var timeAxisHeaderOffset = -_timeline.MediaBackground.ViewOffset.Y - timeAxisOverlap;
|
||||||
|
|
||||||
var moveColor = style.ProgressNormal;
|
var moveColor = style.ProgressNormal;
|
||||||
var thickness = 2.0f;
|
var thickness = 2.0f;
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
private TimeIntervalsHeader _timeIntervalsHeader;
|
private TimeIntervalsHeader _timeIntervalsHeader;
|
||||||
private ContainerControl _backgroundScroll;
|
private ContainerControl _backgroundScroll;
|
||||||
private Background _background;
|
private Background _background;
|
||||||
private Panel _backgroundArea;
|
private BackgroundArea _backgroundArea;
|
||||||
private TimelineEdge _leftEdge;
|
private TimelineEdge _leftEdge;
|
||||||
private TimelineEdge _rightEdge;
|
private TimelineEdge _rightEdge;
|
||||||
private Button _addTrackButton;
|
private Button _addTrackButton;
|
||||||
@@ -305,6 +305,7 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
private PositionHandle _positionHandle;
|
private PositionHandle _positionHandle;
|
||||||
private bool _isRightMouseButtonDown;
|
private bool _isRightMouseButtonDown;
|
||||||
private Vector2 _rightMouseButtonDownPos;
|
private Vector2 _rightMouseButtonDownPos;
|
||||||
|
private Vector2 _rightMouseButtonMovePos;
|
||||||
private float _zoom = 1.0f;
|
private float _zoom = 1.0f;
|
||||||
private bool _isMovingPositionHandle;
|
private bool _isMovingPositionHandle;
|
||||||
private bool _canPlayPauseStop = true;
|
private bool _canPlayPauseStop = true;
|
||||||
@@ -579,7 +580,7 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
get => _zoom;
|
get => _zoom;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
value = Mathf.Clamp(value, 0.0001f, 1000.0f);
|
value = Mathf.Clamp(value, 0.00001f, 1000.0f);
|
||||||
if (Mathf.NearEqual(_zoom, value))
|
if (Mathf.NearEqual(_zoom, value))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -912,7 +913,7 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
Offsets = new Margin(0, 0, 0, HeaderTopAreaHeight),
|
Offsets = new Margin(0, 0, 0, HeaderTopAreaHeight),
|
||||||
Parent = _splitter.Panel2
|
Parent = _splitter.Panel2
|
||||||
};
|
};
|
||||||
_backgroundArea = new Panel(ScrollBars.Both)
|
_backgroundArea = new BackgroundArea(this)
|
||||||
{
|
{
|
||||||
AutoFocus = false,
|
AutoFocus = false,
|
||||||
ClipChildren = false,
|
ClipChildren = false,
|
||||||
@@ -958,12 +959,12 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
private void UpdatePositionHandle()
|
private void UpdatePositionHandle()
|
||||||
{
|
{
|
||||||
var handleWidth = 12.0f;
|
var handleWidth = 12.0f;
|
||||||
_positionHandle.Bounds = new Rectangle(
|
var bounds = new Rectangle();
|
||||||
StartOffset * 2.0f - handleWidth * 0.5f + _currentFrame / _framesPerSecond * UnitsPerSecond * Zoom,
|
bounds.Location.X = StartOffset * 2.0f - handleWidth * 0.5f + _currentFrame / _framesPerSecond * UnitsPerSecond * Zoom;
|
||||||
HeaderTopAreaHeight * -0.5f,
|
bounds.Location.Y = 0;
|
||||||
handleWidth,
|
bounds.Size.X = handleWidth;
|
||||||
HeaderTopAreaHeight * 0.5f
|
bounds.Size.Y = HeaderTopAreaHeight * 0.5f;
|
||||||
);
|
_positionHandle.Bounds = bounds;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnFpsPopupShowing(ComboBox comboBox)
|
private void OnFpsPopupShowing(ComboBox comboBox)
|
||||||
@@ -1039,6 +1040,13 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
|
|
||||||
menu.AddButton("Show preview values", () => ShowPreviewValues = !ShowPreviewValues).Checked = ShowPreviewValues;
|
menu.AddButton("Show preview values", () => ShowPreviewValues = !ShowPreviewValues).Checked = ShowPreviewValues;
|
||||||
|
|
||||||
|
{
|
||||||
|
var zoom = menu.AddButton("Zoom");
|
||||||
|
var zoomValue = new FloatValueBox(Zoom, 140, 2, 50.0f, 0.00001f, 1000.0f, 0.001f);
|
||||||
|
zoomValue.Parent = zoom;
|
||||||
|
zoomValue.ValueChanged += () => Zoom = zoomValue.Value;
|
||||||
|
}
|
||||||
|
|
||||||
OnShowViewContextMenu(menu);
|
OnShowViewContextMenu(menu);
|
||||||
|
|
||||||
menu.Show(_viewButton.Parent, _viewButton.BottomLeft);
|
menu.Show(_viewButton.Parent, _viewButton.BottomLeft);
|
||||||
@@ -1935,8 +1943,8 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
_background.Bounds = new Rectangle(StartOffset, 0, Duration * UnitsPerSecond * Zoom, height);
|
_background.Bounds = new Rectangle(StartOffset, 0, Duration * UnitsPerSecond * Zoom, height);
|
||||||
|
|
||||||
var edgeWidth = 6.0f;
|
var edgeWidth = 6.0f;
|
||||||
_leftEdge.Bounds = new Rectangle(_background.Left - edgeWidth * 0.5f + StartOffset, HeaderTopAreaHeight * -0.5f, edgeWidth, height + HeaderTopAreaHeight * 0.5f);
|
_leftEdge.Bounds = new Rectangle(_background.Left - edgeWidth * 0.5f + StartOffset, 0, edgeWidth, height);
|
||||||
_rightEdge.Bounds = new Rectangle(_background.Right - edgeWidth * 0.5f + StartOffset, HeaderTopAreaHeight * -0.5f, edgeWidth, height + HeaderTopAreaHeight * 0.5f);
|
_rightEdge.Bounds = new Rectangle(_background.Right - edgeWidth * 0.5f + StartOffset, 0, edgeWidth, height);
|
||||||
|
|
||||||
_backgroundScroll.Bounds = new Rectangle(0, 0, _background.Width + 5 * StartOffset, height);
|
_backgroundScroll.Bounds = new Rectangle(0, 0, _background.Width + 5 * StartOffset, height);
|
||||||
}
|
}
|
||||||
@@ -1954,6 +1962,38 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void ShowContextMenu(Vector2 location)
|
||||||
|
{
|
||||||
|
if (!ContainsFocus)
|
||||||
|
Focus();
|
||||||
|
|
||||||
|
var controlUnderMouse = GetChildAtRecursive(location);
|
||||||
|
var mediaUnderMouse = controlUnderMouse;
|
||||||
|
while (mediaUnderMouse != null && !(mediaUnderMouse is Media))
|
||||||
|
{
|
||||||
|
mediaUnderMouse = mediaUnderMouse.Parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
var menu = new ContextMenu.ContextMenu();
|
||||||
|
if (mediaUnderMouse is Media media)
|
||||||
|
{
|
||||||
|
media.OnTimelineShowContextMenu(menu, controlUnderMouse);
|
||||||
|
if (media.PropertiesEditObject != null)
|
||||||
|
{
|
||||||
|
menu.AddButton("Edit media", () => ShowEditPopup(media.PropertiesEditObject, ref location, media.Track));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (PropertiesEditObject != null)
|
||||||
|
{
|
||||||
|
menu.AddButton("Edit timeline", () => ShowEditPopup(PropertiesEditObject, ref location, this));
|
||||||
|
}
|
||||||
|
menu.AddSeparator();
|
||||||
|
menu.AddButton("Reset zoom", () => Zoom = 1.0f);
|
||||||
|
menu.AddButton("Show whole timeline", ShowWholeTimeline);
|
||||||
|
OnShowContextMenu(menu);
|
||||||
|
menu.Show(this, location);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void PerformLayoutBeforeChildren()
|
protected override void PerformLayoutBeforeChildren()
|
||||||
{
|
{
|
||||||
@@ -1986,8 +2026,8 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
{
|
{
|
||||||
_isRightMouseButtonDown = true;
|
_isRightMouseButtonDown = true;
|
||||||
_rightMouseButtonDownPos = location;
|
_rightMouseButtonDownPos = location;
|
||||||
|
_rightMouseButtonMovePos = location;
|
||||||
Focus();
|
Focus();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2006,38 +2046,8 @@ namespace FlaxEditor.GUI.Timeline
|
|||||||
if (button == MouseButton.Right && _isRightMouseButtonDown)
|
if (button == MouseButton.Right && _isRightMouseButtonDown)
|
||||||
{
|
{
|
||||||
_isRightMouseButtonDown = false;
|
_isRightMouseButtonDown = false;
|
||||||
|
|
||||||
if (Vector2.Distance(ref location, ref _rightMouseButtonDownPos) < 4.0f)
|
if (Vector2.Distance(ref location, ref _rightMouseButtonDownPos) < 4.0f)
|
||||||
{
|
ShowContextMenu(location);
|
||||||
if (!ContainsFocus)
|
|
||||||
Focus();
|
|
||||||
|
|
||||||
var controlUnderMouse = GetChildAtRecursive(location);
|
|
||||||
var mediaUnderMouse = controlUnderMouse;
|
|
||||||
while (mediaUnderMouse != null && !(mediaUnderMouse is Media))
|
|
||||||
{
|
|
||||||
mediaUnderMouse = mediaUnderMouse.Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
var menu = new ContextMenu.ContextMenu();
|
|
||||||
if (mediaUnderMouse is Media media)
|
|
||||||
{
|
|
||||||
media.OnTimelineShowContextMenu(menu, controlUnderMouse);
|
|
||||||
if (media.PropertiesEditObject != null)
|
|
||||||
{
|
|
||||||
menu.AddButton("Edit media", () => ShowEditPopup(media.PropertiesEditObject, ref location, media.Track));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (PropertiesEditObject != null)
|
|
||||||
{
|
|
||||||
menu.AddButton("Edit timeline", () => ShowEditPopup(PropertiesEditObject, ref location, this));
|
|
||||||
}
|
|
||||||
menu.AddSeparator();
|
|
||||||
menu.AddButton("Reset zoom", () => Zoom = 1.0f);
|
|
||||||
menu.AddButton("Show whole timeline", ShowWholeTimeline);
|
|
||||||
OnShowContextMenu(menu);
|
|
||||||
menu.Show(this, location);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return base.OnMouseUp(location, button);
|
return base.OnMouseUp(location, button);
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
|||||||
{
|
{
|
||||||
if (selection.Count == 1 && selection[0] is ActorNode actorNode && actorNode.Actor && IsActorValid(actorNode.Actor))
|
if (selection.Count == 1 && selection[0] is ActorNode actorNode && actorNode.Actor && IsActorValid(actorNode.Actor))
|
||||||
{
|
{
|
||||||
menu.AddButton("Select " + actorNode.Actor, OnClickedSelectActor);
|
menu.AddButton("Select " + actorNode.Actor, OnClickedSelectActor).TooltipText = Utilities.Utils.GetTooltip(actorNode.Actor);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Reflection;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using FlaxEditor.CustomEditors;
|
using FlaxEditor.CustomEditors;
|
||||||
using FlaxEditor.GUI.ContextMenu;
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
|
using FlaxEditor.Scripting;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
using FlaxEngine.GUI;
|
using FlaxEngine.GUI;
|
||||||
|
|
||||||
@@ -197,8 +198,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
|||||||
AddMemberTag tag;
|
AddMemberTag tag;
|
||||||
tag.Member = m;
|
tag.Member = m;
|
||||||
tag.Archetype = EventTrack.GetArchetype();
|
tag.Archetype = EventTrack.GetArchetype();
|
||||||
|
var tooltip = Surface.SurfaceUtils.GetVisualScriptMemberInfoDescription(new ScriptMemberInfo(m));
|
||||||
menu.AddButton(sb.ToString(), OnAddMemberTrack).Tag = tag;
|
menu.AddButton(sb.ToString(), OnAddMemberTrack).LinkTooltip(tooltip).Tag = tag;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +296,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
|||||||
AddMemberTag tag;
|
AddMemberTag tag;
|
||||||
tag.Member = m;
|
tag.Member = m;
|
||||||
tag.Archetype = archetype;
|
tag.Archetype = archetype;
|
||||||
menu.AddButton(name + " " + m.Name, OnAddMemberTrack).Tag = tag;
|
var tooltip = Surface.SurfaceUtils.GetVisualScriptMemberInfoDescription(new ScriptMemberInfo(m));
|
||||||
|
menu.AddButton(name + " " + m.Name, OnAddMemberTrack).LinkTooltip(tooltip).Tag = tag;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,13 @@ namespace FlaxEditor.Gizmo
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Performs scene objects snapping to the ground.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void SnapToGround()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Draws the gizmo.
|
/// Draws the gizmo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -89,5 +89,10 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// Gets a <see cref="FlaxEditor.Undo"/> object used by the gizmo owner.
|
/// Gets a <see cref="FlaxEditor.Undo"/> object used by the gizmo owner.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Undo Undo { get; }
|
Undo Undo { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the root tree node for the scene graph.
|
||||||
|
/// </summary>
|
||||||
|
SceneGraph.RootNode SceneGraphRoot { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -218,6 +218,12 @@ namespace FlaxEditor.Gizmo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsSelected(SceneGraphNode obj)
|
||||||
|
{
|
||||||
|
return _selection.Contains(obj);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnApplyTransformation(ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta)
|
protected override void OnApplyTransformation(ref Vector3 translationDelta, ref Quaternion rotationDelta, ref Vector3 scaleDelta)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
namespace FlaxEditor.Gizmo
|
namespace FlaxEditor.Gizmo
|
||||||
@@ -398,15 +399,7 @@ namespace FlaxEditor.Gizmo
|
|||||||
// Snap to ground
|
// Snap to ground
|
||||||
if (_activeAxis == Axis.None && SelectionCount != 0 && Owner.SnapToGround)
|
if (_activeAxis == Axis.None && SelectionCount != 0 && Owner.SnapToGround)
|
||||||
{
|
{
|
||||||
if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false))
|
SnapToGround();
|
||||||
{
|
|
||||||
StartTransforming();
|
|
||||||
var translationDelta = hit.Point - Position;
|
|
||||||
var rotationDelta = Quaternion.Identity;
|
|
||||||
var scaleDelta = Vector3.Zero;
|
|
||||||
OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
|
|
||||||
EndTransforming();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Only when is active
|
// Only when is active
|
||||||
else if (_isActive)
|
else if (_isActive)
|
||||||
@@ -517,6 +510,39 @@ namespace FlaxEditor.Gizmo
|
|||||||
UpdateMatrices();
|
UpdateMatrices();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void SnapToGround()
|
||||||
|
{
|
||||||
|
if (Owner.SceneGraphRoot == null)
|
||||||
|
return;
|
||||||
|
var ray = new Ray(Position, Vector3.Down);
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var view = new Ray(Owner.ViewPosition, Owner.ViewDirection);
|
||||||
|
var rayCastFlags = SceneGraphNode.RayCastData.FlagTypes.SkipEditorPrimitives;
|
||||||
|
var hit = Owner.SceneGraphRoot.RayCast(ref ray, ref view, out var distance, out _, rayCastFlags);
|
||||||
|
if (hit != null)
|
||||||
|
{
|
||||||
|
// Skip snapping selection to itself
|
||||||
|
if (IsSelected(hit))
|
||||||
|
{
|
||||||
|
GetSelectedObjectsBounds(out var selectionBounds, out _);
|
||||||
|
ray.Position = ray.GetPoint(selectionBounds.Size.Y * 0.5f);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snap
|
||||||
|
StartTransforming();
|
||||||
|
var translationDelta = ray.GetPoint(distance) - Position;
|
||||||
|
var rotationDelta = Quaternion.Identity;
|
||||||
|
var scaleDelta = Vector3.Zero;
|
||||||
|
OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
|
||||||
|
EndTransforming();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this tool can transform objects.
|
/// Gets a value indicating whether this tool can transform objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -545,6 +571,13 @@ namespace FlaxEditor.Gizmo
|
|||||||
/// <param name="navigationDirty">True if editing the selected objects transformations marks the navigation system area dirty (for auto-rebuild), otherwise skip update.</param>
|
/// <param name="navigationDirty">True if editing the selected objects transformations marks the navigation system area dirty (for auto-rebuild), otherwise skip update.</param>
|
||||||
protected abstract void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty);
|
protected abstract void GetSelectedObjectsBounds(out BoundingBox bounds, out bool navigationDirty);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the specified object is selected.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to check.</param>
|
||||||
|
/// <returns>True if it's selected, otherwise false.</returns>
|
||||||
|
protected abstract bool IsSelected(SceneGraphNode obj);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called when user starts transforming selected objects.
|
/// Called when user starts transforming selected objects.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ ManagedEditor::~ManagedEditor()
|
|||||||
void ManagedEditor::Init()
|
void ManagedEditor::Init()
|
||||||
{
|
{
|
||||||
// Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time
|
// Note: editor modules should perform quite fast init, any longer things should be done in async during 'editor splash screen time
|
||||||
void* args[3];
|
void* args[4];
|
||||||
MClass* mclass = GetClass();
|
MClass* mclass = GetClass();
|
||||||
if (mclass == nullptr)
|
if (mclass == nullptr)
|
||||||
{
|
{
|
||||||
@@ -194,14 +194,16 @@ void ManagedEditor::Init()
|
|||||||
MonoObject* exception = nullptr;
|
MonoObject* exception = nullptr;
|
||||||
bool isHeadless = CommandLine::Options.Headless.IsTrue();
|
bool isHeadless = CommandLine::Options.Headless.IsTrue();
|
||||||
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
|
bool skipCompile = CommandLine::Options.SkipCompile.IsTrue();
|
||||||
|
bool newProject = CommandLine::Options.NewProject.IsTrue();
|
||||||
args[0] = &isHeadless;
|
args[0] = &isHeadless;
|
||||||
args[1] = &skipCompile;
|
args[1] = &skipCompile;
|
||||||
|
args[2] = &newProject;
|
||||||
Guid sceneId;
|
Guid sceneId;
|
||||||
if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId)))
|
if (!CommandLine::Options.Play.HasValue() || (CommandLine::Options.Play.HasValue() && Guid::Parse(CommandLine::Options.Play.GetValue(), sceneId)))
|
||||||
{
|
{
|
||||||
sceneId = Guid::Empty;
|
sceneId = Guid::Empty;
|
||||||
}
|
}
|
||||||
args[2] = &sceneId;
|
args[3] = &sceneId;
|
||||||
initMethod->Invoke(instance, args, &exception);
|
initMethod->Invoke(instance, args, &exception);
|
||||||
if (exception)
|
if (exception)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FlaxEditor.Actions;
|
using FlaxEditor.Actions;
|
||||||
using FlaxEditor.Content;
|
using FlaxEditor.Content;
|
||||||
@@ -49,8 +50,20 @@ namespace FlaxEditor.Modules
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public void CreatePrefab()
|
public void CreatePrefab()
|
||||||
{
|
{
|
||||||
// Check selection
|
CreatePrefab(Editor.SceneEditing.Selection);
|
||||||
var selection = Editor.SceneEditing.Selection;
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Starts the creating prefab for the selected actor by showing the new item creation dialog in <see cref="ContentWindow"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// To create prefab manually (from code) use <see cref="PrefabManager.CreatePrefab"/> method.
|
||||||
|
/// </remarks>
|
||||||
|
/// <param name="selection">The scene selection to use.</param>
|
||||||
|
public void CreatePrefab(List<SceneGraphNode> selection)
|
||||||
|
{
|
||||||
|
if (selection == null)
|
||||||
|
selection = Editor.SceneEditing.Selection;
|
||||||
if (selection.Count == 1 && selection[0] is ActorNode actorNode && actorNode.CanCreatePrefab)
|
if (selection.Count == 1 && selection[0] is ActorNode actorNode && actorNode.CanCreatePrefab)
|
||||||
{
|
{
|
||||||
CreatePrefab(actorNode.Actor);
|
CreatePrefab(actorNode.Actor);
|
||||||
|
|||||||
@@ -216,7 +216,7 @@ namespace FlaxEditor.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDirty(IEnumerable<SceneGraphNode> objects)
|
private void OnDirty(List<SceneGraphNode> objects)
|
||||||
{
|
{
|
||||||
var options = Editor.Options.Options;
|
var options = Editor.Options.Options;
|
||||||
var isPlayMode = Editor.StateMachine.IsPlayMode;
|
var isPlayMode = Editor.StateMachine.IsPlayMode;
|
||||||
@@ -236,7 +236,7 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
foreach (var obj in objects)
|
foreach (var obj in objects)
|
||||||
{
|
{
|
||||||
if (obj is ActorNode node && node.Actor.Scene && node.AffectsNavigationWithChildren)
|
if (obj is ActorNode node && node.Actor && node.Actor.Scene && node.AffectsNavigationWithChildren)
|
||||||
{
|
{
|
||||||
var bounds = node.Actor.BoxWithChildren;
|
var bounds = node.Actor.BoxWithChildren;
|
||||||
Navigation.BuildNavMesh(node.Actor.Scene, bounds, options.General.AutoRebuildNavMeshTimeoutMs);
|
Navigation.BuildNavMesh(node.Actor.Scene, bounds, options.General.AutoRebuildNavMeshTimeoutMs);
|
||||||
@@ -303,26 +303,28 @@ namespace FlaxEditor.Modules
|
|||||||
{
|
{
|
||||||
if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode))
|
if (!Editor.SceneEditing.HasSthSelected || !(Editor.SceneEditing.Selection[0] is ActorNode))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Level.IsAnySceneLoaded == false)
|
if (Level.IsAnySceneLoaded == false)
|
||||||
throw new InvalidOperationException("Cannot spawn actor when no scene is loaded.");
|
throw new InvalidOperationException("Cannot spawn actor when no scene is loaded.");
|
||||||
|
|
||||||
var actionList = new IUndoAction[4];
|
var actionList = new IUndoAction[4];
|
||||||
Actor old = ((ActorNode)Editor.SceneEditing.Selection[0]).Actor;
|
var oldNode = (ActorNode)Editor.SceneEditing.Selection[0];
|
||||||
Actor actor = (Actor)FlaxEngine.Object.New(to);
|
var old = oldNode.Actor;
|
||||||
|
var actor = (Actor)FlaxEngine.Object.New(to);
|
||||||
var parent = old.Parent;
|
var parent = old.Parent;
|
||||||
var orderInParent = old.OrderInParent;
|
var orderInParent = old.OrderInParent;
|
||||||
|
|
||||||
|
// Steps:
|
||||||
|
// - deselect old actor
|
||||||
|
// - destroy old actor
|
||||||
|
// - spawn new actor
|
||||||
|
// - select new actor
|
||||||
|
|
||||||
SelectionDeleteBegin?.Invoke();
|
SelectionDeleteBegin?.Invoke();
|
||||||
|
|
||||||
actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);
|
actionList[0] = new SelectionChangeAction(Selection.ToArray(), new SceneGraphNode[0], OnSelectionUndo);
|
||||||
actionList[0].Do();
|
actionList[0].Do();
|
||||||
|
|
||||||
actionList[1] = new DeleteActorsAction(new List<SceneGraphNode>
|
actionList[1] = new DeleteActorsAction(oldNode.BuildAllNodes().Where(x => x.CanDelete).ToList());
|
||||||
{
|
|
||||||
Editor.Instance.Scene.GetActorNode(old)
|
|
||||||
});
|
|
||||||
actionList[1].Do();
|
|
||||||
|
|
||||||
SelectionDeleteEnd?.Invoke();
|
SelectionDeleteEnd?.Invoke();
|
||||||
|
|
||||||
@@ -345,17 +347,12 @@ namespace FlaxEditor.Modules
|
|||||||
actor.StaticFlags = StaticFlags.None;
|
actor.StaticFlags = StaticFlags.None;
|
||||||
|
|
||||||
// Move children
|
// Move children
|
||||||
for (var i = old.ScriptsCount - 1; i >= 0; i--)
|
var scripts = old.Scripts;
|
||||||
{
|
for (var i = scripts.Length - 1; i >= 0; i--)
|
||||||
var script = old.Scripts[i];
|
scripts[i].Actor = actor;
|
||||||
script.Actor = actor;
|
var children = old.Children;
|
||||||
Guid newid = Guid.NewGuid();
|
for (var i = children.Length - 1; i >= 0; i--)
|
||||||
FlaxEngine.Object.Internal_ChangeID(FlaxEngine.Object.GetUnmanagedPtr(script), ref newid);
|
children[i].Parent = actor;
|
||||||
}
|
|
||||||
for (var i = old.Children.Length - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
old.Children[i].Parent = actor;
|
|
||||||
}
|
|
||||||
|
|
||||||
var actorNode = Editor.Instance.Scene.GetActorNode(actor);
|
var actorNode = Editor.Instance.Scene.GetActorNode(actor);
|
||||||
if (actorNode == null)
|
if (actorNode == null)
|
||||||
@@ -364,16 +361,13 @@ namespace FlaxEditor.Modules
|
|||||||
actorNode.PostSpawn();
|
actorNode.PostSpawn();
|
||||||
Editor.Scene.MarkSceneEdited(actor.Scene);
|
Editor.Scene.MarkSceneEdited(actor.Scene);
|
||||||
|
|
||||||
actionList[2] = new DeleteActorsAction(new List<SceneGraphNode>
|
actionList[1].Do();
|
||||||
{
|
actionList[2] = new DeleteActorsAction(actorNode.BuildAllNodes().Where(x => x.CanDelete).ToList(), true);
|
||||||
actorNode
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo);
|
actionList[3] = new SelectionChangeAction(new SceneGraphNode[0], new SceneGraphNode[] { actorNode }, OnSelectionUndo);
|
||||||
actionList[3].Do();
|
actionList[3].Do();
|
||||||
|
|
||||||
var actions = new MultiUndoAction(actionList);
|
Undo.AddAction(new MultiUndoAction(actionList, "Convert actor"));
|
||||||
Undo.AddAction(actions);
|
|
||||||
|
|
||||||
SpawnEnd?.Invoke();
|
SpawnEnd?.Invoke();
|
||||||
|
|
||||||
@@ -389,6 +383,7 @@ namespace FlaxEditor.Modules
|
|||||||
var objects = Selection.Where(x => x.CanDelete).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();
|
var objects = Selection.Where(x => x.CanDelete).ToList().BuildAllNodes().Where(x => x.CanDelete).ToList();
|
||||||
if (objects.Count == 0)
|
if (objects.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
var isSceneTreeFocus = Editor.Windows.SceneWin.ContainsFocus;
|
||||||
|
|
||||||
SelectionDeleteBegin?.Invoke();
|
SelectionDeleteBegin?.Invoke();
|
||||||
|
|
||||||
@@ -410,6 +405,9 @@ namespace FlaxEditor.Modules
|
|||||||
SelectionDeleteEnd?.Invoke();
|
SelectionDeleteEnd?.Invoke();
|
||||||
|
|
||||||
OnDirty(objects);
|
OnDirty(objects);
|
||||||
|
|
||||||
|
if (isSceneTreeFocus)
|
||||||
|
Editor.Windows.SceneWin.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -251,6 +251,15 @@ namespace FlaxEditor.Modules
|
|||||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// In play-mode Editor mocks the level streaming script
|
||||||
|
if (Editor.IsPlayMode)
|
||||||
|
{
|
||||||
|
if (!additive)
|
||||||
|
Level.UnloadAllScenesAsync();
|
||||||
|
Level.LoadSceneAsync(sceneId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!additive)
|
if (!additive)
|
||||||
{
|
{
|
||||||
// Ensure to save all pending changes
|
// Ensure to save all pending changes
|
||||||
@@ -272,6 +281,13 @@ namespace FlaxEditor.Modules
|
|||||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// In play-mode Editor mocks the level streaming script
|
||||||
|
if (Editor.IsPlayMode)
|
||||||
|
{
|
||||||
|
Level.UnloadSceneAsync(scene);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure to save all pending changes
|
// Ensure to save all pending changes
|
||||||
if (CheckSaveBeforeClose())
|
if (CheckSaveBeforeClose())
|
||||||
return;
|
return;
|
||||||
@@ -289,6 +305,13 @@ namespace FlaxEditor.Modules
|
|||||||
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
if (!Editor.StateMachine.CurrentState.CanChangeScene)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// In play-mode Editor mocks the level streaming script
|
||||||
|
if (Editor.IsPlayMode)
|
||||||
|
{
|
||||||
|
Level.UnloadAllScenesAsync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure to save all pending changes
|
// Ensure to save all pending changes
|
||||||
if (CheckSaveBeforeClose())
|
if (CheckSaveBeforeClose())
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using FlaxEditor.GUI.ContextMenu;
|
||||||
using FlaxEditor.SceneGraph.GUI;
|
using FlaxEditor.SceneGraph.GUI;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
@@ -17,9 +19,6 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether this scene is edited.
|
/// Gets or sets a value indicating whether this scene is edited.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
|
||||||
/// <c>true</c> if this scene is edited; otherwise, <c>false</c>.
|
|
||||||
/// </value>
|
|
||||||
public bool IsEdited
|
public bool IsEdited
|
||||||
{
|
{
|
||||||
get => _isEdited;
|
get => _isEdited;
|
||||||
@@ -28,7 +27,6 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
if (_isEdited != value)
|
if (_isEdited != value)
|
||||||
{
|
{
|
||||||
_isEdited = value;
|
_isEdited = value;
|
||||||
|
|
||||||
_treeNode.UpdateText();
|
_treeNode.UpdateText();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,9 +35,6 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the scene.
|
/// Gets the scene.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
|
||||||
/// The scene.
|
|
||||||
/// </value>
|
|
||||||
public Scene Scene => _actor as Scene;
|
public Scene Scene => _actor as Scene;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -68,5 +63,37 @@ namespace FlaxEditor.SceneGraph.Actors
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override SceneNode ParentScene => this;
|
public override SceneNode ParentScene => this;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void OnContextMenu(ContextMenu contextMenu)
|
||||||
|
{
|
||||||
|
contextMenu.AddSeparator();
|
||||||
|
var path = Scene.Path;
|
||||||
|
if (!string.IsNullOrEmpty(path) && File.Exists(path))
|
||||||
|
{
|
||||||
|
var b = contextMenu.AddButton("Show in content window", OnSelect);
|
||||||
|
b.Icon = Editor.Instance.Icons.Search12;
|
||||||
|
b.TooltipText = "Finds and selects the scene asset int Content window.";
|
||||||
|
}
|
||||||
|
contextMenu.AddButton("Save scene", OnSave).LinkTooltip("Saves this scene.").Enabled = IsEdited && !Editor.IsPlayMode;
|
||||||
|
contextMenu.AddButton("Unload scene", OnUnload).LinkTooltip("Unloads this scene.").Enabled = Editor.Instance.StateMachine.CurrentState.CanChangeScene;
|
||||||
|
|
||||||
|
base.OnContextMenu(contextMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelect()
|
||||||
|
{
|
||||||
|
Editor.Instance.Windows.ContentWin.Select(Editor.Instance.ContentDatabase.Find(Scene.Path));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSave()
|
||||||
|
{
|
||||||
|
Editor.Instance.Scene.SaveScene(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUnload()
|
||||||
|
{
|
||||||
|
Editor.Instance.Scene.CloseScene(Scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -134,7 +134,8 @@ namespace FlaxEditor.SceneGraph
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Try to pick custom node type for that actor object
|
// Try to pick custom node type for that actor object
|
||||||
if (CustomNodesTypes.TryGetValue(actor.GetType(), out customType))
|
var type = actor.GetType();
|
||||||
|
if (CustomNodesTypes.TryGetValue(type, out customType))
|
||||||
{
|
{
|
||||||
// Use custom type
|
// Use custom type
|
||||||
_sharedArgsContainer[0] = actor;
|
_sharedArgsContainer[0] = actor;
|
||||||
@@ -142,8 +143,21 @@ namespace FlaxEditor.SceneGraph
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Check if the actor type inherits from one of the custom types but doesn't provide own node type
|
||||||
|
foreach (var e in CustomNodesTypes)
|
||||||
|
{
|
||||||
|
if (e.Key.IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
// Use custom type
|
||||||
|
_sharedArgsContainer[0] = actor;
|
||||||
|
result = (ActorNode)Activator.CreateInstance(e.Value, _sharedArgsContainer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Use default type for actors
|
// Use default type for actors
|
||||||
result = new ActorNode(actor);
|
if (result == null)
|
||||||
|
result = new ActorNode(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build children
|
// Build children
|
||||||
|
|||||||
@@ -125,5 +125,33 @@ namespace FlaxEditor.SceneGraph
|
|||||||
FillTree(target, result);
|
FillTree(target, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the list made of all nodes in the input scene tree root and child tree. The result collection contains all nodes in the tree.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">The node.</param>
|
||||||
|
/// <returns>The result.</returns>
|
||||||
|
public static List<SceneGraphNode> BuildAllNodes<T>(this T node)
|
||||||
|
where T : SceneGraphNode
|
||||||
|
{
|
||||||
|
var list = new List<SceneGraphNode>();
|
||||||
|
BuildAllNodes(node, list);
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Builds the list made of all nodes in the input scene tree root and child tree. The result collection contains all nodes in the tree.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">The node.</param>
|
||||||
|
/// <param name="result">The result.</param>
|
||||||
|
public static void BuildAllNodes<T>(this T node, List<SceneGraphNode> result)
|
||||||
|
where T : SceneGraphNode
|
||||||
|
{
|
||||||
|
if (node == null || result == null)
|
||||||
|
throw new ArgumentNullException();
|
||||||
|
result.Clear();
|
||||||
|
result.Add(node);
|
||||||
|
FillTree(node, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,10 +135,15 @@ bool sortInstallations(RiderInstallation* const& i1, RiderInstallation* const& i
|
|||||||
int32 version2[3] = { 0 };
|
int32 version2[3] = { 0 };
|
||||||
StringUtils::Parse(values1[0].Get(), &version1[0]);
|
StringUtils::Parse(values1[0].Get(), &version1[0]);
|
||||||
StringUtils::Parse(values1[1].Get(), &version1[1]);
|
StringUtils::Parse(values1[1].Get(), &version1[1]);
|
||||||
StringUtils::Parse(values1[2].Get(), &version1[2]);
|
|
||||||
|
if(values1.Count() > 2)
|
||||||
|
StringUtils::Parse(values1[2].Get(), &version1[2]);
|
||||||
|
|
||||||
StringUtils::Parse(values2[0].Get(), &version2[0]);
|
StringUtils::Parse(values2[0].Get(), &version2[0]);
|
||||||
StringUtils::Parse(values2[1].Get(), &version2[1]);
|
StringUtils::Parse(values2[1].Get(), &version2[1]);
|
||||||
StringUtils::Parse(values2[2].Get(), &version2[2]);
|
|
||||||
|
if(values2.Count() > 2)
|
||||||
|
StringUtils::Parse(values2[2].Get(), &version2[2]);
|
||||||
|
|
||||||
// Compare by MAJOR.MINOR.BUILD
|
// Compare by MAJOR.MINOR.BUILD
|
||||||
if (version1[0] == version2[0])
|
if (version1[0] == version2[0])
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ namespace FlaxEditor.States
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool CanEditScene => true;
|
public override bool CanEditScene => true;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override bool CanChangeScene => true;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool CanUseUndoRedo => false;
|
public override bool CanUseUndoRedo => false;
|
||||||
|
|
||||||
@@ -89,9 +92,13 @@ namespace FlaxEditor.States
|
|||||||
{
|
{
|
||||||
Profiler.BeginEvent("PlayingState.CacheSelection");
|
Profiler.BeginEvent("PlayingState.CacheSelection");
|
||||||
_selectedObjects.Clear();
|
_selectedObjects.Clear();
|
||||||
for (int i = 0; i < Editor.SceneEditing.Selection.Count; i++)
|
var selection = Editor.SceneEditing.Selection;
|
||||||
|
if (selection.Count != 0)
|
||||||
{
|
{
|
||||||
_selectedObjects.Add(Editor.SceneEditing.Selection[i].ID);
|
for (int i = 0; i < selection.Count; i++)
|
||||||
|
_selectedObjects.Add(selection[i].ID);
|
||||||
|
selection.Clear();
|
||||||
|
Editor.SceneEditing.OnSelectionChanged();
|
||||||
}
|
}
|
||||||
Profiler.EndEvent();
|
Profiler.EndEvent();
|
||||||
}
|
}
|
||||||
@@ -99,15 +106,16 @@ namespace FlaxEditor.States
|
|||||||
private void RestoreSelection()
|
private void RestoreSelection()
|
||||||
{
|
{
|
||||||
Profiler.BeginEvent("PlayingState.RestoreSelection");
|
Profiler.BeginEvent("PlayingState.RestoreSelection");
|
||||||
var count = Editor.SceneEditing.Selection.Count;
|
var selection = Editor.SceneEditing.Selection;
|
||||||
Editor.SceneEditing.Selection.Clear();
|
var count = selection.Count;
|
||||||
|
selection.Clear();
|
||||||
for (int i = 0; i < _selectedObjects.Count; i++)
|
for (int i = 0; i < _selectedObjects.Count; i++)
|
||||||
{
|
{
|
||||||
var node = SceneGraphFactory.FindNode(_selectedObjects[i]);
|
var node = SceneGraphFactory.FindNode(_selectedObjects[i]);
|
||||||
if (node != null)
|
if (node != null)
|
||||||
Editor.SceneEditing.Selection.Add(node);
|
selection.Add(node);
|
||||||
}
|
}
|
||||||
if (Editor.SceneEditing.Selection.Count != count)
|
if (selection.Count != count)
|
||||||
Editor.SceneEditing.OnSelectionChanged();
|
Editor.SceneEditing.OnSelectionChanged();
|
||||||
Profiler.EndEvent();
|
Profiler.EndEvent();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,10 +122,7 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
{
|
{
|
||||||
GetBox(0).CurrentType = type;
|
GetBox(0).CurrentType = type;
|
||||||
Title = (_isUnpacking ? "Unpack " : "Pack ") + type.Name;
|
Title = (_isUnpacking ? "Unpack " : "Pack ") + type.Name;
|
||||||
var attributes = type.GetAttributes(false);
|
TooltipText = SurfaceUtils.GetVisualScriptTypeDescription(type);
|
||||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
|
||||||
if (tooltipAttribute != null)
|
|
||||||
TooltipText += "\n" + tooltipAttribute.Text;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -92,6 +92,7 @@ namespace FlaxEditor.Surface
|
|||||||
case MaterialParameterType.GPUTexture: return typeof(GPUTexture);
|
case MaterialParameterType.GPUTexture: return typeof(GPUTexture);
|
||||||
case MaterialParameterType.Matrix: return typeof(Matrix);
|
case MaterialParameterType.Matrix: return typeof(Matrix);
|
||||||
case MaterialParameterType.ChannelMask: return typeof(ChannelMask);
|
case MaterialParameterType.ChannelMask: return typeof(ChannelMask);
|
||||||
|
case MaterialParameterType.TextureGroupSampler: return typeof(int);
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -427,6 +428,22 @@ namespace FlaxEditor.Surface
|
|||||||
return !TypeUtils.IsDelegate(managedType);
|
return !TypeUtils.IsDelegate(managedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string GetVisualScriptTypeDescription(ScriptType type)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
if (type.IsStatic)
|
||||||
|
sb.Append("static ");
|
||||||
|
else if (type.IsAbstract)
|
||||||
|
sb.Append("abstract ");
|
||||||
|
sb.Append(type.TypeName);
|
||||||
|
|
||||||
|
var attributes = type.GetAttributes(false);
|
||||||
|
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
||||||
|
if (tooltipAttribute != null)
|
||||||
|
sb.Append("\n").Append(tooltipAttribute.Text);
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
internal static string GetVisualScriptMemberInfoDescription(ScriptMemberInfo member)
|
internal static string GetVisualScriptMemberInfoDescription(ScriptMemberInfo member)
|
||||||
{
|
{
|
||||||
var name = member.Name;
|
var name = member.Name;
|
||||||
|
|||||||
@@ -604,7 +604,7 @@ namespace FlaxEditor.Surface
|
|||||||
Parent = this
|
Parent = this
|
||||||
};
|
};
|
||||||
|
|
||||||
Presenter = new CustomEditorPresenter(undo);
|
Presenter = new CustomEditorPresenter(undo, "Loading...");
|
||||||
Presenter.Panel.Parent = scrollPanel;
|
Presenter.Panel.Parent = scrollPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -744,7 +744,7 @@ namespace FlaxEditor.Surface
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_propertiesEditor = new CustomEditorPresenter(_undo);
|
_propertiesEditor = new CustomEditorPresenter(_undo, "Loading...");
|
||||||
_propertiesEditor.Panel.Parent = _split2.Panel2;
|
_propertiesEditor.Panel.Parent = _split2.Panel2;
|
||||||
}
|
}
|
||||||
_propertiesEditor.Modified += OnPropertyEdited;
|
_propertiesEditor.Modified += OnPropertyEdited;
|
||||||
@@ -896,6 +896,16 @@ namespace FlaxEditor.Surface
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called when surface gets loaded and user can edit it.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnSurfaceEditingStart()
|
||||||
|
{
|
||||||
|
_undo.Clear();
|
||||||
|
_surface.Enabled = true;
|
||||||
|
_propertiesEditor.BuildLayout();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the surface from the asset. Called during <see cref="Update"/> when asset is loaded and surface is missing.
|
/// Loads the surface from the asset. Called during <see cref="Update"/> when asset is loaded and surface is missing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -939,10 +949,7 @@ namespace FlaxEditor.Surface
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup
|
OnSurfaceEditingStart();
|
||||||
_undo.Clear();
|
|
||||||
_surface.Enabled = true;
|
|
||||||
_propertiesEditor.BuildLayout();
|
|
||||||
ClearEditedFlag();
|
ClearEditedFlag();
|
||||||
if (_showWholeGraphOnLoad)
|
if (_showWholeGraphOnLoad)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using FlaxEditor.Gizmo;
|
using FlaxEditor.Gizmo;
|
||||||
|
using FlaxEditor.SceneGraph;
|
||||||
using FlaxEditor.Tools.Foliage.Undo;
|
using FlaxEditor.Tools.Foliage.Undo;
|
||||||
using FlaxEngine;
|
using FlaxEngine;
|
||||||
|
|
||||||
@@ -87,6 +88,12 @@ namespace FlaxEditor.Tools.Foliage
|
|||||||
navigationDirty = false;
|
navigationDirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override bool IsSelected(SceneGraphNode obj)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnStartTransforming()
|
protected override void OnStartTransforming()
|
||||||
{
|
{
|
||||||
@@ -231,6 +238,21 @@ namespace FlaxEditor.Tools.Foliage
|
|||||||
Owner.Undo?.AddAction(action);
|
Owner.Undo?.AddAction(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override void SnapToGround()
|
||||||
|
{
|
||||||
|
if (Physics.RayCast(Position, Vector3.Down, out var hit, float.MaxValue, uint.MaxValue, false))
|
||||||
|
{
|
||||||
|
// Snap
|
||||||
|
StartTransforming();
|
||||||
|
var translationDelta = hit.Point - Position;
|
||||||
|
var rotationDelta = Quaternion.Identity;
|
||||||
|
var scaleDelta = Vector3.Zero;
|
||||||
|
OnApplyTransformation(ref translationDelta, ref rotationDelta, ref scaleDelta);
|
||||||
|
EndTransforming();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnActivated()
|
public override void OnActivated()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -135,6 +135,7 @@ namespace FlaxEditor.Actions
|
|||||||
node.Delete();
|
node.Delete();
|
||||||
}
|
}
|
||||||
_nodeParents.Clear();
|
_nodeParents.Clear();
|
||||||
|
FlaxEngine.Scripting.FlushRemovedObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -141,15 +141,20 @@ namespace FlaxEditor.Actions
|
|||||||
for (int i = 0; i < nodeParents.Count; i++)
|
for (int i = 0; i < nodeParents.Count; i++)
|
||||||
{
|
{
|
||||||
var node = nodeParents[i];
|
var node = nodeParents[i];
|
||||||
var parent = node.Actor?.Parent;
|
var actor = node.Actor;
|
||||||
|
var parent = actor?.Parent;
|
||||||
if (parent != null)
|
if (parent != null)
|
||||||
{
|
{
|
||||||
// Fix name collisions
|
// Fix name collisions
|
||||||
string name = node.Name;
|
var name = actor.Name;
|
||||||
Actor[] children = parent.Children;
|
for (int j = 0; j < parent.ChildrenCount; j++)
|
||||||
if (children.Any(x => x.Name == name))
|
|
||||||
{
|
{
|
||||||
node.Actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
|
var child = parent.Children[j];
|
||||||
|
if (child != actor && child.Name == actor.Name)
|
||||||
|
{
|
||||||
|
var children = parent.Children;
|
||||||
|
actor.Name = StringUtils.IncrementNameNumber(name, x => children.All(y => y.Name != x));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,18 @@ namespace FlaxEditor.Utilities
|
|||||||
return string.Format("{0:0.##} {1}", bytes, MemorySizePostfixes[order]);
|
return string.Format("{0:0.##} {1}", bytes, MemorySizePostfixes[order]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static string GetTooltip(SceneObject obj)
|
||||||
|
{
|
||||||
|
var str = obj is Actor actor ? actor.Name : TypeUtils.GetObjectType(obj).Name;
|
||||||
|
var o = obj.Parent;
|
||||||
|
while (o)
|
||||||
|
{
|
||||||
|
str = o.Name + " -> " + str;
|
||||||
|
o = o.Parent;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The colors for the keyframes used by the curve editor.
|
/// The colors for the keyframes used by the curve editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ namespace FlaxEditor.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="task">The task.</param>
|
/// <param name="task">The task.</param>
|
||||||
/// <param name="undo">The undo.</param>
|
/// <param name="undo">The undo.</param>
|
||||||
public EditorGizmoViewport(SceneRenderTask task, Undo undo)
|
/// <param name="sceneGraphRoot">The scene graph root.</param>
|
||||||
|
public EditorGizmoViewport(SceneRenderTask task, Undo undo, SceneGraph.RootNode sceneGraphRoot)
|
||||||
: base(task, new FPSCamera(), true)
|
: base(task, new FPSCamera(), true)
|
||||||
{
|
{
|
||||||
Undo = undo;
|
Undo = undo;
|
||||||
|
SceneGraphRoot = sceneGraphRoot;
|
||||||
|
|
||||||
SetUpdate(ref _update, OnUpdate);
|
SetUpdate(ref _update, OnUpdate);
|
||||||
}
|
}
|
||||||
@@ -73,6 +75,9 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Undo Undo { get; }
|
public Undo Undo { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public SceneGraph.RootNode SceneGraphRoot { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
protected override bool IsControllingMouse => Gizmos.Active?.IsControllingMouse ?? false;
|
||||||
|
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ namespace FlaxEditor.Viewport
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="editor">Editor instance.</param>
|
/// <param name="editor">Editor instance.</param>
|
||||||
public MainEditorGizmoViewport(Editor editor)
|
public MainEditorGizmoViewport(Editor editor)
|
||||||
: base(Object.New<SceneRenderTask>(), editor.Undo)
|
: base(Object.New<SceneRenderTask>(), editor.Undo, editor.Scene.Root)
|
||||||
{
|
{
|
||||||
_editor = editor;
|
_editor = editor;
|
||||||
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
_dragAssets = new DragAssets<DragDropEventArgs>(ValidateDragItem);
|
||||||
|
|||||||
@@ -336,6 +336,9 @@ namespace FlaxEditor.Viewport
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Undo Undo { get; }
|
public Undo Undo { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public RootNode SceneGraphRoot => _window.Graph.Root;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public EditorViewport Viewport => this;
|
public EditorViewport Viewport => this;
|
||||||
|
|
||||||
|
|||||||
@@ -186,7 +186,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Asset properties proxy
|
// Asset properties proxy
|
||||||
_properties = new PropertiesProxy();
|
_properties = new PropertiesProxy();
|
||||||
_propertiesEditor.Select(_properties);
|
|
||||||
|
|
||||||
// Preview properties editor
|
// Preview properties editor
|
||||||
_previewTab = new Tab("Preview");
|
_previewTab = new Tab("Preview");
|
||||||
@@ -322,22 +321,17 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
Editor.LogError("Failed to save animation graph surface");
|
Editor.LogError("Failed to save animation graph surface");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save data to the temporary asset
|
|
||||||
if (_asset.SaveSurface(value))
|
if (_asset.SaveSurface(value))
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
_surface.MarkAsEdited();
|
_surface.MarkAsEdited();
|
||||||
Editor.LogError("Failed to save animation graph surface data");
|
Editor.LogError("Failed to save animation graph surface data");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_asset.Reload();
|
_asset.Reload();
|
||||||
|
_asset.WaitForLoaded();
|
||||||
// Reset any root motion
|
|
||||||
_preview.PreviewActor.ResetLocalTransform();
|
_preview.PreviewActor.ResetLocalTransform();
|
||||||
_previewTab.Presenter.BuildLayoutOnUpdate();
|
_previewTab.Presenter.BuildLayoutOnUpdate();
|
||||||
}
|
}
|
||||||
@@ -376,6 +370,14 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnSurfaceEditingStart()
|
||||||
|
{
|
||||||
|
_propertiesEditor.Select(_properties);
|
||||||
|
|
||||||
|
base.OnSurfaceEditingStart();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void PerformLayoutBeforeChildren()
|
protected override void PerformLayoutBeforeChildren()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -229,7 +229,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
layout.Label("No parameters");
|
layout.Label("No parameters");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!materialInstance.IsLoaded || materialInstance.BaseMaterial && !materialInstance.BaseMaterial.IsLoaded)
|
if (!materialInstance.IsLoaded || (materialInstance.BaseMaterial && !materialInstance.BaseMaterial.IsLoaded))
|
||||||
{
|
{
|
||||||
layout.Label("Loading...");
|
layout.Label("Loading...");
|
||||||
return;
|
return;
|
||||||
@@ -352,10 +352,9 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Material properties editor
|
// Material properties editor
|
||||||
_editor = new CustomEditorPresenter(_undo);
|
_editor = new CustomEditorPresenter(_undo, "Loading...");
|
||||||
_editor.Panel.Parent = _split.Panel2;
|
_editor.Panel.Parent = _split.Panel2;
|
||||||
_properties = new PropertiesProxy();
|
_properties = new PropertiesProxy();
|
||||||
_editor.Select(_properties);
|
|
||||||
_editor.Modified += OnMaterialPropertyEdited;
|
_editor.Modified += OnMaterialPropertyEdited;
|
||||||
|
|
||||||
// Setup input actions
|
// Setup input actions
|
||||||
@@ -479,16 +478,11 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(float deltaTime)
|
public override void Update(float deltaTime)
|
||||||
{
|
{
|
||||||
// Check if need to load
|
|
||||||
if (_isWaitingForLoad && _asset.IsLoaded && (_asset.BaseMaterial == null || _asset.BaseMaterial.IsLoaded))
|
if (_isWaitingForLoad && _asset.IsLoaded && (_asset.BaseMaterial == null || _asset.BaseMaterial.IsLoaded))
|
||||||
{
|
{
|
||||||
// Clear flag
|
|
||||||
_isWaitingForLoad = false;
|
_isWaitingForLoad = false;
|
||||||
|
|
||||||
// Init material properties and parameters proxy
|
|
||||||
_properties.OnLoad(this);
|
_properties.OnLoad(this);
|
||||||
|
_editor.Select(_properties);
|
||||||
// Setup
|
|
||||||
ClearEditedFlag();
|
ClearEditedFlag();
|
||||||
_undo.Clear();
|
_undo.Clear();
|
||||||
_editor.BuildLayout();
|
_editor.BuildLayout();
|
||||||
|
|||||||
@@ -222,7 +222,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Asset properties proxy
|
// Asset properties proxy
|
||||||
_properties = new PropertiesProxy();
|
_properties = new PropertiesProxy();
|
||||||
_propertiesEditor.Select(_properties);
|
|
||||||
|
|
||||||
// Surface
|
// Surface
|
||||||
_surface = new MaterialSurface(this, Save, _undo)
|
_surface = new MaterialSurface(this, Save, _undo)
|
||||||
@@ -324,17 +323,14 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
get => _asset.LoadSurface(true);
|
get => _asset.LoadSurface(true);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// Create material info
|
|
||||||
FillMaterialInfo(out var info);
|
FillMaterialInfo(out var info);
|
||||||
|
|
||||||
// Save data to the temporary material
|
|
||||||
if (_asset.SaveSurface(value, info))
|
if (_asset.SaveSurface(value, info))
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
_surface.MarkAsEdited();
|
_surface.MarkAsEdited();
|
||||||
Editor.LogError("Failed to save material surface data");
|
Editor.LogError("Failed to save material surface data");
|
||||||
}
|
}
|
||||||
_asset.Reload();
|
_asset.Reload();
|
||||||
|
_asset.WaitForLoaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +343,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
// Load surface graph
|
// Load surface graph
|
||||||
if (_surface.Load())
|
if (_surface.Load())
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
Editor.LogError("Failed to load material surface.");
|
Editor.LogError("Failed to load material surface.");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -362,6 +357,14 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnSurfaceEditingStart()
|
||||||
|
{
|
||||||
|
_propertiesEditor.Select(_properties);
|
||||||
|
|
||||||
|
base.OnSurfaceEditingStart();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override bool CanEditSurfaceOnAssetLoadError => true;
|
protected override bool CanEditSurfaceOnAssetLoadError => true;
|
||||||
|
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
// Asset properties proxy
|
// Asset properties proxy
|
||||||
_properties = new PropertiesProxy();
|
_properties = new PropertiesProxy();
|
||||||
_propertiesEditor.Select(_properties);
|
|
||||||
|
|
||||||
// Preview properties editor
|
// Preview properties editor
|
||||||
_previewTab = new Tab("Preview");
|
_previewTab = new Tab("Preview");
|
||||||
@@ -217,14 +216,13 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
get => _asset.LoadSurface(true);
|
get => _asset.LoadSurface(true);
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
// Save data to the temporary asset
|
|
||||||
if (_asset.SaveSurface(value))
|
if (_asset.SaveSurface(value))
|
||||||
{
|
{
|
||||||
// Error
|
|
||||||
_surface.MarkAsEdited();
|
_surface.MarkAsEdited();
|
||||||
Editor.LogError("Failed to save Particle Emitter surface data");
|
Editor.LogError("Failed to save Particle Emitter surface data");
|
||||||
}
|
}
|
||||||
_asset.Reload();
|
_asset.Reload();
|
||||||
|
_asset.WaitForLoaded();
|
||||||
_preview.PreviewActor.ResetSimulation();
|
_preview.PreviewActor.ResetSimulation();
|
||||||
_previewTab.Presenter.BuildLayoutOnUpdate();
|
_previewTab.Presenter.BuildLayoutOnUpdate();
|
||||||
}
|
}
|
||||||
@@ -255,6 +253,14 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void OnSurfaceEditingStart()
|
||||||
|
{
|
||||||
|
_propertiesEditor.Select(_properties);
|
||||||
|
|
||||||
|
base.OnSurfaceEditingStart();
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override bool SaveToOriginal()
|
protected override bool SaveToOriginal()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ namespace FlaxEditor.Windows.Assets
|
|||||||
|
|
||||||
contextMenu.AddSeparator();
|
contextMenu.AddSeparator();
|
||||||
|
|
||||||
b = contextMenu.AddButton("Create Prefab", Editor.Prefabs.CreatePrefab);
|
b = contextMenu.AddButton("Create Prefab", () => Editor.Prefabs.CreatePrefab(Selection));
|
||||||
b.Enabled = isSingleActorSelected &&
|
b.Enabled = isSingleActorSelected &&
|
||||||
(Selection[0] as ActorNode).CanCreatePrefab &&
|
(Selection[0] as ActorNode).CanCreatePrefab &&
|
||||||
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
|
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
|
|
||||||
_view.IsSearching = true;
|
_view.IsSearching = true;
|
||||||
_view.ShowItems(items);
|
_view.ShowItems(items, _sortType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters)
|
private void UpdateItemsSearchFilter(ContentFolder folder, List<ContentItem> items, bool[] filters)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ namespace FlaxEditor.Windows
|
|||||||
private TextBox _foldersSearchBox;
|
private TextBox _foldersSearchBox;
|
||||||
private TextBox _itemsSearchBox;
|
private TextBox _itemsSearchBox;
|
||||||
private ViewDropdown _viewDropdown;
|
private ViewDropdown _viewDropdown;
|
||||||
|
private SortType _sortType;
|
||||||
|
|
||||||
private RootContentTreeNode _root;
|
private RootContentTreeNode _root;
|
||||||
|
|
||||||
@@ -215,6 +216,20 @@ namespace FlaxEditor.Windows
|
|||||||
filterButton.Checked = _viewDropdown.IsSelected(filterButton.Text);
|
filterButton.Checked = _viewDropdown.IsSelected(filterButton.Text);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var sortBy = menu.AddChildMenu("Sort by");
|
||||||
|
sortBy.ContextMenu.AddButton("Alphabetic Order", OnSortByButtonClicked).Tag = SortType.AlphabeticOrder;
|
||||||
|
sortBy.ContextMenu.AddButton("Alphabetic Reverse", OnSortByButtonClicked).Tag = SortType.AlphabeticReverse;
|
||||||
|
sortBy.ContextMenu.VisibleChanged += control =>
|
||||||
|
{
|
||||||
|
if (!control.Visible)
|
||||||
|
return;
|
||||||
|
foreach (var item in ((ContextMenu)control).Items)
|
||||||
|
{
|
||||||
|
if (item is ContextMenuButton button)
|
||||||
|
button.Checked = _sortType == (SortType)button.Tag;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return menu;
|
return menu;
|
||||||
}
|
}
|
||||||
@@ -230,6 +245,18 @@ namespace FlaxEditor.Windows
|
|||||||
_viewDropdown.OnClicked(i);
|
_viewDropdown.OnClicked(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnSortByButtonClicked(ContextMenuButton button)
|
||||||
|
{
|
||||||
|
switch ((SortType)button.Tag)
|
||||||
|
{
|
||||||
|
case SortType.AlphabeticOrder: _sortType = SortType.AlphabeticOrder;
|
||||||
|
break;
|
||||||
|
case SortType.AlphabeticReverse: _sortType = SortType.AlphabeticReverse;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
RefreshView(SelectedNode);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Shows popup dialog with UI to rename content item.
|
/// Shows popup dialog with UI to rename content item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -701,12 +728,12 @@ namespace FlaxEditor.Windows
|
|||||||
items.Add(node.Folder);
|
items.Add(node.Folder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_view.ShowItems(items);
|
_view.ShowItems(items, _sortType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Show folder contents
|
// Show folder contents
|
||||||
_view.ShowItems(target.Folder.Children);
|
_view.ShowItems(target.Folder.Children, _sortType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -446,12 +446,18 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct QueueItem
|
||||||
|
{
|
||||||
|
public string PresetName;
|
||||||
|
public BuildTarget Target;
|
||||||
|
}
|
||||||
|
|
||||||
private PresetsColumn _presets;
|
private PresetsColumn _presets;
|
||||||
private TargetsColumn _targets;
|
private TargetsColumn _targets;
|
||||||
private int _selectedPresetIndex = -1;
|
private int _selectedPresetIndex = -1;
|
||||||
private int _selectedTargetIndex = -1;
|
private int _selectedTargetIndex = -1;
|
||||||
private CustomEditorPresenter _targetSettings;
|
private CustomEditorPresenter _targetSettings;
|
||||||
private readonly Queue<BuildTarget> _buildingQueue = new Queue<BuildTarget>();
|
private readonly Queue<QueueItem> _buildingQueue = new Queue<QueueItem>();
|
||||||
private string _preBuildAction;
|
private string _preBuildAction;
|
||||||
private string _postBuildAction;
|
private string _postBuildAction;
|
||||||
private BuildPreset[] _data;
|
private BuildPreset[] _data;
|
||||||
@@ -489,14 +495,14 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
// Execute pre-build action
|
// Execute pre-build action
|
||||||
if (!string.IsNullOrEmpty(_preBuildAction))
|
if (!string.IsNullOrEmpty(_preBuildAction))
|
||||||
ExecueAction(_preBuildAction);
|
ExecuteAction(_preBuildAction);
|
||||||
_preBuildAction = null;
|
_preBuildAction = null;
|
||||||
}
|
}
|
||||||
else if (type == GameCooker.EventType.BuildDone)
|
else if (type == GameCooker.EventType.BuildDone)
|
||||||
{
|
{
|
||||||
// Execute post-build action
|
// Execute post-build action
|
||||||
if (!string.IsNullOrEmpty(_postBuildAction))
|
if (!string.IsNullOrEmpty(_postBuildAction))
|
||||||
ExecueAction(_postBuildAction);
|
ExecuteAction(_postBuildAction);
|
||||||
_postBuildAction = null;
|
_postBuildAction = null;
|
||||||
}
|
}
|
||||||
else if (type == GameCooker.EventType.BuildFailed)
|
else if (type == GameCooker.EventType.BuildFailed)
|
||||||
@@ -506,7 +512,7 @@ namespace FlaxEditor.Windows
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ExecueAction(string action)
|
private void ExecuteAction(string action)
|
||||||
{
|
{
|
||||||
string command = "echo off\ncd \"" + Globals.ProjectFolder.Replace('/', '\\') + "\"\necho on\n" + action;
|
string command = "echo off\ncd \"" + Globals.ProjectFolder.Replace('/', '\\') + "\"\necho on\n" + action;
|
||||||
command = command.Replace("\n", "\r\n");
|
command = command.Replace("\n", "\r\n");
|
||||||
@@ -545,21 +551,30 @@ namespace FlaxEditor.Windows
|
|||||||
Editor.Log("Building all targets");
|
Editor.Log("Building all targets");
|
||||||
foreach (var e in preset.Targets)
|
foreach (var e in preset.Targets)
|
||||||
{
|
{
|
||||||
_buildingQueue.Enqueue(e.DeepClone());
|
_buildingQueue.Enqueue(new QueueItem
|
||||||
|
{
|
||||||
|
PresetName = preset.Name,
|
||||||
|
Target = e.DeepClone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Builds the target.
|
/// Builds the target.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="preset">The preset.</param>
|
||||||
/// <param name="target">The target.</param>
|
/// <param name="target">The target.</param>
|
||||||
public void Build(BuildTarget target)
|
public void Build(BuildPreset preset, BuildTarget target)
|
||||||
{
|
{
|
||||||
if (target == null)
|
if (target == null)
|
||||||
throw new ArgumentNullException(nameof(target));
|
throw new ArgumentNullException(nameof(target));
|
||||||
|
|
||||||
Editor.Log("Building target");
|
Editor.Log("Building target");
|
||||||
_buildingQueue.Enqueue(target.DeepClone());
|
_buildingQueue.Enqueue(new QueueItem
|
||||||
|
{
|
||||||
|
PresetName = preset.Name,
|
||||||
|
Target = target.DeepClone(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildTarget()
|
private void BuildTarget()
|
||||||
@@ -569,7 +584,8 @@ namespace FlaxEditor.Windows
|
|||||||
if (_data[_selectedPresetIndex].Targets == null || _data[_selectedPresetIndex].Targets.Length <= _selectedTargetIndex)
|
if (_data[_selectedPresetIndex].Targets == null || _data[_selectedPresetIndex].Targets.Length <= _selectedTargetIndex)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Build(_data[_selectedPresetIndex].Targets[_selectedTargetIndex]);
|
var preset = _data[_selectedPresetIndex];
|
||||||
|
Build(preset, preset.Targets[_selectedTargetIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BuildAllTargets()
|
private void BuildAllTargets()
|
||||||
@@ -825,12 +841,13 @@ namespace FlaxEditor.Windows
|
|||||||
{
|
{
|
||||||
if (_buildingQueue.Count > 0)
|
if (_buildingQueue.Count > 0)
|
||||||
{
|
{
|
||||||
var target = _buildingQueue.Dequeue();
|
var item = _buildingQueue.Dequeue();
|
||||||
|
var target = item.Target;
|
||||||
|
|
||||||
_preBuildAction = target.PreBuildAction;
|
_preBuildAction = target.PreBuildAction;
|
||||||
_postBuildAction = target.PostBuildAction;
|
_postBuildAction = target.PostBuildAction;
|
||||||
|
|
||||||
GameCooker.Build(target.Platform, target.Mode, target.Output, BuildOptions.None, target.CustomDefines);
|
GameCooker.Build(target.Platform, target.Mode, target.Output, BuildOptions.None, target.CustomDefines, item.PresetName, target.Name);
|
||||||
}
|
}
|
||||||
else if (_exitOnBuildEnd)
|
else if (_exitOnBuildEnd)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ namespace FlaxEditor.Windows
|
|||||||
: base(editor, true, ScrollBars.Vertical)
|
: base(editor, true, ScrollBars.Vertical)
|
||||||
{
|
{
|
||||||
Title = "Properties";
|
Title = "Properties";
|
||||||
|
AutoFocus = true;
|
||||||
|
|
||||||
Presenter = new CustomEditorPresenter(editor.Undo);
|
Presenter = new CustomEditorPresenter(editor.Undo);
|
||||||
Presenter.Panel.Parent = this;
|
Presenter.Panel.Parent = this;
|
||||||
|
|||||||
@@ -104,12 +104,11 @@ namespace FlaxEditor.Windows
|
|||||||
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
|
Editor.Windows.ContentWin.CurrentViewFolder.CanHaveAssets;
|
||||||
|
|
||||||
bool hasPrefabLink = canEditScene && isSingleActorSelected && (Editor.SceneEditing.Selection[0] as ActorNode).HasPrefabLink;
|
bool hasPrefabLink = canEditScene && isSingleActorSelected && (Editor.SceneEditing.Selection[0] as ActorNode).HasPrefabLink;
|
||||||
|
if (hasPrefabLink)
|
||||||
b = contextMenu.AddButton("Select Prefab", Editor.Prefabs.SelectPrefab);
|
{
|
||||||
b.Enabled = hasPrefabLink;
|
contextMenu.AddButton("Select Prefab", Editor.Prefabs.SelectPrefab);
|
||||||
|
contextMenu.AddButton("Break Prefab Link", Editor.Prefabs.BreakLinks);
|
||||||
b = contextMenu.AddButton("Break Prefab Link", Editor.Prefabs.BreakLinks);
|
}
|
||||||
b.Enabled = hasPrefabLink;
|
|
||||||
|
|
||||||
// Spawning actors options
|
// Spawning actors options
|
||||||
|
|
||||||
|
|||||||
@@ -204,14 +204,7 @@ namespace FlaxEditor.Windows
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = _groupSearch.AddChild(CreateActorItem(CustomEditors.CustomEditorsUtil.GetPropertyNameUI(text), actorType));
|
var item = _groupSearch.AddChild(CreateActorItem(CustomEditors.CustomEditorsUtil.GetPropertyNameUI(text), actorType));
|
||||||
item.TooltipText = actorType.TypeName;
|
item.TooltipText = Surface.SurfaceUtils.GetVisualScriptTypeDescription(actorType);
|
||||||
var attributes = actorType.GetAttributes(false);
|
|
||||||
var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute);
|
|
||||||
if (tooltipAttribute != null)
|
|
||||||
{
|
|
||||||
item.TooltipText += '\n';
|
|
||||||
item.TooltipText += tooltipAttribute.Text;
|
|
||||||
}
|
|
||||||
|
|
||||||
var highlights = new List<Rectangle>(ranges.Length);
|
var highlights = new List<Rectangle>(ranges.Length);
|
||||||
var style = Style.Current;
|
var style = Style.Current;
|
||||||
|
|||||||
@@ -236,23 +236,24 @@ void SceneAnimationPlayer::MapTrack(const StringView& from, const Guid& to)
|
|||||||
{
|
{
|
||||||
const auto trackData = track.GetData<SceneAnimation::ActorTrack::Data>();
|
const auto trackData = track.GetData<SceneAnimation::ActorTrack::Data>();
|
||||||
_objectsMapping[trackData->ID] = to;
|
_objectsMapping[trackData->ID] = to;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case SceneAnimation::Track::Types::Script:
|
case SceneAnimation::Track::Types::Script:
|
||||||
{
|
{
|
||||||
const auto trackData = track.GetData<SceneAnimation::ScriptTrack::Data>();
|
const auto trackData = track.GetData<SceneAnimation::ScriptTrack::Data>();
|
||||||
_objectsMapping[trackData->ID] = to;
|
_objectsMapping[trackData->ID] = to;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
case SceneAnimation::Track::Types::CameraCut:
|
case SceneAnimation::Track::Types::CameraCut:
|
||||||
{
|
{
|
||||||
const auto trackData = track.GetData<SceneAnimation::CameraCutTrack::Data>();
|
const auto trackData = track.GetData<SceneAnimation::CameraCutTrack::Data>();
|
||||||
_objectsMapping[trackData->ID] = to;
|
_objectsMapping[trackData->ID] = to;
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
default: ;
|
default: ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
LOG(Warning, "Missing track '{0}' in scene animation '{1}' to map into object ID={2}", from, anim->ToString(), to);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
void SceneAnimationPlayer::Restore(SceneAnimation* anim, int32 stateIndexOffset)
|
||||||
@@ -744,7 +745,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
|||||||
const auto trackData = track.GetData<SceneAnimation::ActorTrack::Data>();
|
const auto trackData = track.GetData<SceneAnimation::ActorTrack::Data>();
|
||||||
Guid id = trackData->ID;
|
Guid id = trackData->ID;
|
||||||
_objectsMapping.TryGet(id, id);
|
_objectsMapping.TryGet(id, id);
|
||||||
state.Object = Scripting::FindObject<Actor>(trackData->ID);
|
state.Object = Scripting::FindObject<Actor>(id);
|
||||||
if (!state.Object)
|
if (!state.Object)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Failed to find {3} of ID={0} for track '{1}' in scene animation '{2}'", id, track.Name, anim->ToString(), TEXT("actor"));
|
LOG(Warning, "Failed to find {3} of ID={0} for track '{1}' in scene animation '{2}'", id, track.Name, anim->ToString(), TEXT("actor"));
|
||||||
|
|||||||
@@ -1222,6 +1222,11 @@ Asset::LoadResult VisualScript::load()
|
|||||||
method.ProfilerName.Get()[assetName.Length()] = ':';
|
method.ProfilerName.Get()[assetName.Length()] = ':';
|
||||||
method.ProfilerName.Get()[assetName.Length() + 1] = ':';
|
method.ProfilerName.Get()[assetName.Length() + 1] = ':';
|
||||||
Platform::MemoryCopy(method.ProfilerName.Get() + assetName.Length() + 2, method.Name.Get(), method.Name.Length());
|
Platform::MemoryCopy(method.ProfilerName.Get() + assetName.Length() + 2, method.Name.Get(), method.Name.Length());
|
||||||
|
method.ProfilerData.name = method.ProfilerName.Get();
|
||||||
|
method.ProfilerData.function = method.Name.Get();
|
||||||
|
method.ProfilerData.file = nullptr;
|
||||||
|
method.ProfilerData.line = 0;
|
||||||
|
method.ProfilerData.color = 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2139,7 +2144,7 @@ VisualScriptingBinaryModule* VisualScripting::GetBinaryModule()
|
|||||||
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span<Variant> parameters)
|
Variant VisualScripting::Invoke(VisualScript::Method* method, ScriptingObject* instance, Span<Variant> parameters)
|
||||||
{
|
{
|
||||||
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
|
CHECK_RETURN(method && method->Script->IsLoaded(), Variant::Zero);
|
||||||
PROFILE_CPU_NAMED(*method->ProfilerName);
|
PROFILE_CPU_SRC_LOC(method->ProfilerData);
|
||||||
|
|
||||||
// Add to the calling stack
|
// Add to the calling stack
|
||||||
ScopeContext scope;
|
ScopeContext scope;
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
#include "../BinaryAsset.h"
|
#include "../BinaryAsset.h"
|
||||||
#include "Engine/Scripting/BinaryModule.h"
|
#include "Engine/Scripting/BinaryModule.h"
|
||||||
#include "Engine/Visject/VisjectGraph.h"
|
#include "Engine/Visject/VisjectGraph.h"
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
#include "Engine/Profiler/ProfilerSrcLoc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define VISUAL_SCRIPT_GRAPH_MAX_CALL_STACK 250
|
#define VISUAL_SCRIPT_GRAPH_MAX_CALL_STACK 250
|
||||||
#define VISUAL_SCRIPT_DEBUGGING USE_EDITOR
|
#define VISUAL_SCRIPT_DEBUGGING USE_EDITOR
|
||||||
@@ -118,6 +121,7 @@ public:
|
|||||||
Array<StringAnsi, InlinedAllocation<16>> ParamNames;
|
Array<StringAnsi, InlinedAllocation<16>> ParamNames;
|
||||||
#if COMPILE_WITH_PROFILER
|
#if COMPILE_WITH_PROFILER
|
||||||
StringAnsi ProfilerName;
|
StringAnsi ProfilerName;
|
||||||
|
SourceLocationData ProfilerData;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -296,7 +296,7 @@ namespace FlaxEditor.Content.Settings
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create new settings asset and link it to the game settings
|
// Create new settings asset and link it to the game settings
|
||||||
var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, CustomEditors.CustomEditorsUtil.GetPropertyNameUI(typeof(T).Name) + ".json");
|
var path = StringUtils.CombinePaths(Globals.ProjectContentFolder, "Settings", CustomEditors.CustomEditorsUtil.GetPropertyNameUI(typeof(T).Name) + ".json");
|
||||||
if (Editor.SaveJsonAsset(path, obj))
|
if (Editor.SaveJsonAsset(path, obj))
|
||||||
return true;
|
return true;
|
||||||
asset = FlaxEngine.Content.LoadAsync<JsonAsset>(path);
|
asset = FlaxEngine.Content.LoadAsync<JsonAsset>(path);
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ bool CommandLine::Parse(const Char* cmdLine)
|
|||||||
PARSE_BOOL_SWITCH("-clearcache ", ClearCache);
|
PARSE_BOOL_SWITCH("-clearcache ", ClearCache);
|
||||||
PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache);
|
PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache);
|
||||||
PARSE_ARG_SWITCH("-project ", Project);
|
PARSE_ARG_SWITCH("-project ", Project);
|
||||||
|
PARSE_BOOL_SWITCH("-new ", NewProject);
|
||||||
PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles);
|
PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles);
|
||||||
PARSE_ARG_SWITCH("-build ", Build);
|
PARSE_ARG_SWITCH("-build ", Build);
|
||||||
PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile);
|
PARSE_BOOL_SWITCH("-skipcompile ", SkipCompile);
|
||||||
|
|||||||
@@ -134,6 +134,11 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
String Project;
|
String Project;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// -new (generates the project files inside the specified project folder or uses current workspace folder)
|
||||||
|
/// </summary>
|
||||||
|
Nullable<bool> NewProject;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// -genprojectfiles (generates the scripts project files)
|
/// -genprojectfiles (generates the scripts project files)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -156,8 +156,7 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks whenever the game viewport is focused by the user (eg. can receive input).
|
/// Checks whenever the game viewport is focused by the user (eg. can receive input).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if game viewport is focused, otherwise false.</returns>
|
API_PROPERTY() static bool HasGameViewportFocus();
|
||||||
static bool HasGameViewportFocus();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Update() override;
|
void Update() override;
|
||||||
|
void Dispose() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
InputService InputServiceInstance;
|
InputService InputServiceInstance;
|
||||||
@@ -914,3 +915,24 @@ void InputService::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InputService::Dispose()
|
||||||
|
{
|
||||||
|
// Dispose input devices
|
||||||
|
if (Input::Mouse)
|
||||||
|
{
|
||||||
|
Input::Mouse->DeleteObject();
|
||||||
|
Input::Mouse = nullptr;
|
||||||
|
}
|
||||||
|
if (Input::Keyboard)
|
||||||
|
{
|
||||||
|
Input::Keyboard->DeleteObject();
|
||||||
|
Input::Keyboard = nullptr;
|
||||||
|
}
|
||||||
|
for (int32 i = 0; i < Input::Gamepads.Count(); i++)
|
||||||
|
Input::Gamepads[i]->DeleteObject();
|
||||||
|
Input::Gamepads.Clear();
|
||||||
|
for (int32 i = 0; i < Input::CustomDevices.Count(); i++)
|
||||||
|
Input::CustomDevices[i]->DeleteObject();
|
||||||
|
Input::CustomDevices.Clear();
|
||||||
|
}
|
||||||
|
|||||||
@@ -1611,21 +1611,22 @@ bool Actor::FromBytes(const Span<byte>& data, Array<Actor*>& output, ISerializeM
|
|||||||
|
|
||||||
// Create object
|
// Create object
|
||||||
auto obj = SceneObjectsFactory::Spawn(document, modifier);
|
auto obj = SceneObjectsFactory::Spawn(document, modifier);
|
||||||
|
sceneObjects->At(i) = obj;
|
||||||
if (obj == nullptr)
|
if (obj == nullptr)
|
||||||
{
|
{
|
||||||
LOG(Warning, "Cannot create object.");
|
LOG(Warning, "Cannot create object.");
|
||||||
return true;
|
continue;
|
||||||
}
|
}
|
||||||
obj->RegisterObject();
|
obj->RegisterObject();
|
||||||
|
|
||||||
// Add to results
|
// Add to results
|
||||||
sceneObjects->At(i) = obj;
|
|
||||||
Actor* actor = dynamic_cast<Actor*>(obj);
|
Actor* actor = dynamic_cast<Actor*>(obj);
|
||||||
if (actor)
|
if (actor)
|
||||||
{
|
{
|
||||||
output.Add(actor);
|
output.Add(actor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: optimize this to call json parsing only once per-object instead of twice (spawn + load)
|
||||||
stream.SetPosition(startPos);
|
stream.SetPosition(startPos);
|
||||||
for (int32 i = 0; i < objectsCount; i++)
|
for (int32 i = 0; i < objectsCount; i++)
|
||||||
{
|
{
|
||||||
@@ -1639,7 +1640,7 @@ bool Actor::FromBytes(const Span<byte>& data, Array<Actor*>& output, ISerializeM
|
|||||||
int32 orderInParent;
|
int32 orderInParent;
|
||||||
stream.ReadInt32(&orderInParent);
|
stream.ReadInt32(&orderInParent);
|
||||||
|
|
||||||
// Load JSON
|
// Load JSON
|
||||||
rapidjson_flax::Document document;
|
rapidjson_flax::Document document;
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED("Json.Parse");
|
PROFILE_CPU_NAMED("Json.Parse");
|
||||||
@@ -1653,7 +1654,10 @@ bool Actor::FromBytes(const Span<byte>& data, Array<Actor*>& output, ISerializeM
|
|||||||
|
|
||||||
// Deserialize object
|
// Deserialize object
|
||||||
auto obj = sceneObjects->At(i);
|
auto obj = sceneObjects->At(i);
|
||||||
SceneObjectsFactory::Deserialize(obj, document, modifier);
|
if (obj)
|
||||||
|
SceneObjectsFactory::Deserialize(obj, document, modifier);
|
||||||
|
else
|
||||||
|
SceneObjectsFactory::HandleObjectDeserializationError(document);
|
||||||
}
|
}
|
||||||
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
Scripting::ObjectsLookupIdMapping.Set(nullptr);
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,11 @@ void BoxVolume::SetSize(const Vector3& value)
|
|||||||
|
|
||||||
#include "Engine/Debug/DebugDraw.h"
|
#include "Engine/Debug/DebugDraw.h"
|
||||||
|
|
||||||
|
Color BoxVolume::GetWiresColor()
|
||||||
|
{
|
||||||
|
return Color::White;
|
||||||
|
}
|
||||||
|
|
||||||
void BoxVolume::OnDebugDraw()
|
void BoxVolume::OnDebugDraw()
|
||||||
{
|
{
|
||||||
const Color color = GetWiresColor();
|
const Color color = GetWiresColor();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
API_CLASS(Abstract) class FLAXENGINE_API BoxVolume : public Actor
|
API_CLASS(Abstract) class FLAXENGINE_API BoxVolume : public Actor
|
||||||
{
|
{
|
||||||
DECLARE_SCENE_OBJECT_ABSTRACT(BoxVolume);
|
DECLARE_SCENE_OBJECT(BoxVolume);
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Vector3 _size;
|
Vector3 _size;
|
||||||
@@ -47,7 +47,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if USE_EDITOR
|
#if USE_EDITOR
|
||||||
virtual Color GetWiresColor() = 0;
|
virtual Color GetWiresColor();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -25,13 +25,13 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The fog density factor.
|
/// The fog density factor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(10), DefaultValue(0.02f), Limit(0.000001f, 0.8f, 0.001f), EditorDisplay(\"Exponential Height Fog\")")
|
API_FIELD(Attributes="EditorOrder(10), DefaultValue(0.02f), Limit(0.0000001f, 100.0f, 0.001f), EditorDisplay(\"Exponential Height Fog\")")
|
||||||
float FogDensity = 0.02f;
|
float FogDensity = 0.02f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The fog height density factor that controls how the density increases as height decreases. The smaller values produce more visible transition larger.
|
/// The fog height density factor that controls how the density increases as height decreases. The smaller values produce more visible transition larger.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="EditorOrder(20), DefaultValue(0.2f), Limit(0.001f, 2.0f, 0.001f), EditorDisplay(\"Exponential Height Fog\")")
|
API_FIELD(Attributes="EditorOrder(20), DefaultValue(0.2f), Limit(0.0001f, 10.0f, 0.001f), EditorDisplay(\"Exponential Height Fog\")")
|
||||||
float FogHeightFalloff = 0.2f;
|
float FogHeightFalloff = 0.2f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ typedef Dictionary<Guid, Actor*, HeapAllocation> ActorsLookup;
|
|||||||
|
|
||||||
#define DECLARE_SCENE_OBJECT_ABSTRACT(type) \
|
#define DECLARE_SCENE_OBJECT_ABSTRACT(type) \
|
||||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(type); \
|
DECLARE_SCRIPTING_TYPE_NO_SPAWN(type); \
|
||||||
|
static type* Spawn(const SpawnParams& params) { return nullptr; } \
|
||||||
explicit type(const SpawnParams& params)
|
explicit type(const SpawnParams& params)
|
||||||
|
|
||||||
#define DECLARE_SCENE_OBJECT_NO_SPAWN(type) \
|
#define DECLARE_SCENE_OBJECT_NO_SPAWN(type) \
|
||||||
|
|||||||
@@ -189,7 +189,12 @@ void LocalizationService::OnLocalizationChanged()
|
|||||||
localeName[currentCulture.Length() + 5] = '8';
|
localeName[currentCulture.Length() + 5] = '8';
|
||||||
localeName[currentCulture.Length() + 6] = 0;
|
localeName[currentCulture.Length() + 6] = 0;
|
||||||
}
|
}
|
||||||
std::locale::global(std::locale(localeName));
|
try
|
||||||
|
{
|
||||||
|
std::locale::global(std::locale(localeName));
|
||||||
|
}
|
||||||
|
catch (std::runtime_error const&) {}
|
||||||
|
catch (...) {}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,11 @@ int32 BoxTrianglesIndicesCache[] =
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define NAV_MESH_TILE_MAX_EXTENT 100000000
|
#define NAV_MESH_TILE_MAX_EXTENT 100000000
|
||||||
|
#define NAV_MESH_BUILD_DEBUG_DRAW_GEOMETRY 0
|
||||||
|
|
||||||
|
#if NAV_MESH_BUILD_DEBUG_DRAW_GEOMETRY
|
||||||
|
#include "Engine/Debug/DebugDraw.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
struct OffMeshLink
|
struct OffMeshLink
|
||||||
{
|
{
|
||||||
@@ -108,6 +113,9 @@ struct NavigationSceneRasterization
|
|||||||
auto v0 = vb[ib[i0++]];
|
auto v0 = vb[ib[i0++]];
|
||||||
auto v1 = vb[ib[i0++]];
|
auto v1 = vb[ib[i0++]];
|
||||||
auto v2 = vb[ib[i0++]];
|
auto v2 = vb[ib[i0++]];
|
||||||
|
#if NAV_MESH_BUILD_DEBUG_DRAW_GEOMETRY
|
||||||
|
DEBUG_DRAW_TRIANGLE(v0, v1, v2, Color::Orange.AlphaMultiplied(0.3f), 1.0f, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
auto n = Vector3::Cross(v0 - v1, v0 - v2);
|
auto n = Vector3::Cross(v0 - v1, v0 - v2);
|
||||||
n.Normalize();
|
n.Normalize();
|
||||||
@@ -124,6 +132,9 @@ struct NavigationSceneRasterization
|
|||||||
auto v0 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
auto v0 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
||||||
auto v1 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
auto v1 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
||||||
auto v2 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
auto v2 = Vector3::Transform(vb[ib[i0++]], worldToNavMesh);
|
||||||
|
#if NAV_MESH_BUILD_DEBUG_DRAW_GEOMETRY
|
||||||
|
DEBUG_DRAW_TRIANGLE(v0, v1, v2, Color::Orange.AlphaMultiplied(0.3f), 1.0f, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
auto n = Vector3::Cross(v0 - v1, v0 - v2);
|
auto n = Vector3::Cross(v0 - v1, v0 - v2);
|
||||||
n.Normalize();
|
n.Normalize();
|
||||||
@@ -223,6 +234,8 @@ struct NavigationSceneRasterization
|
|||||||
// Extract data from the actor
|
// Extract data from the actor
|
||||||
if (const auto* boxCollider = dynamic_cast<BoxCollider*>(actor))
|
if (const auto* boxCollider = dynamic_cast<BoxCollider*>(actor))
|
||||||
{
|
{
|
||||||
|
if (boxCollider->GetIsTrigger())
|
||||||
|
return true;
|
||||||
PROFILE_CPU_NAMED("BoxCollider");
|
PROFILE_CPU_NAMED("BoxCollider");
|
||||||
|
|
||||||
const OrientedBoundingBox box = boxCollider->GetOrientedBox();
|
const OrientedBoundingBox box = boxCollider->GetOrientedBox();
|
||||||
@@ -232,6 +245,8 @@ struct NavigationSceneRasterization
|
|||||||
}
|
}
|
||||||
else if (const auto* sphereCollider = dynamic_cast<SphereCollider*>(actor))
|
else if (const auto* sphereCollider = dynamic_cast<SphereCollider*>(actor))
|
||||||
{
|
{
|
||||||
|
if (sphereCollider->GetIsTrigger())
|
||||||
|
return true;
|
||||||
PROFILE_CPU_NAMED("SphereCollider");
|
PROFILE_CPU_NAMED("SphereCollider");
|
||||||
|
|
||||||
const BoundingSphere sphere = sphereCollider->GetSphere();
|
const BoundingSphere sphere = sphereCollider->GetSphere();
|
||||||
@@ -241,6 +256,8 @@ struct NavigationSceneRasterization
|
|||||||
}
|
}
|
||||||
else if (const auto* capsuleCollider = dynamic_cast<CapsuleCollider*>(actor))
|
else if (const auto* capsuleCollider = dynamic_cast<CapsuleCollider*>(actor))
|
||||||
{
|
{
|
||||||
|
if (capsuleCollider->GetIsTrigger())
|
||||||
|
return true;
|
||||||
PROFILE_CPU_NAMED("CapsuleCollider");
|
PROFILE_CPU_NAMED("CapsuleCollider");
|
||||||
|
|
||||||
const BoundingBox box = capsuleCollider->GetBox();
|
const BoundingBox box = capsuleCollider->GetBox();
|
||||||
@@ -250,6 +267,8 @@ struct NavigationSceneRasterization
|
|||||||
}
|
}
|
||||||
else if (const auto* meshCollider = dynamic_cast<MeshCollider*>(actor))
|
else if (const auto* meshCollider = dynamic_cast<MeshCollider*>(actor))
|
||||||
{
|
{
|
||||||
|
if (meshCollider->GetIsTrigger())
|
||||||
|
return true;
|
||||||
PROFILE_CPU_NAMED("MeshCollider");
|
PROFILE_CPU_NAMED("MeshCollider");
|
||||||
|
|
||||||
auto collisionData = meshCollider->CollisionData.Get();
|
auto collisionData = meshCollider->CollisionData.Get();
|
||||||
@@ -258,10 +277,17 @@ struct NavigationSceneRasterization
|
|||||||
|
|
||||||
collisionData->ExtractGeometry(vb, ib);
|
collisionData->ExtractGeometry(vb, ib);
|
||||||
|
|
||||||
|
Matrix meshColliderToWorld;
|
||||||
|
meshCollider->GetLocalToWorldMatrix(meshColliderToWorld);
|
||||||
|
for (auto& v : vb)
|
||||||
|
Vector3::Transform(v, meshColliderToWorld, v);
|
||||||
|
|
||||||
e.RasterizeTriangles();
|
e.RasterizeTriangles();
|
||||||
}
|
}
|
||||||
else if (const auto* splineCollider = dynamic_cast<SplineCollider*>(actor))
|
else if (const auto* splineCollider = dynamic_cast<SplineCollider*>(actor))
|
||||||
{
|
{
|
||||||
|
if (splineCollider->GetIsTrigger())
|
||||||
|
return true;
|
||||||
PROFILE_CPU_NAMED("SplineCollider");
|
PROFILE_CPU_NAMED("SplineCollider");
|
||||||
|
|
||||||
auto collisionData = splineCollider->CollisionData.Get();
|
auto collisionData = splineCollider->CollisionData.Get();
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ void ENetDriver::Disconnect(const NetworkConnection& connection)
|
|||||||
void* peer = nullptr;
|
void* peer = nullptr;
|
||||||
if(_peerMap.TryGet(connectionId, peer))
|
if(_peerMap.TryGet(connectionId, peer))
|
||||||
{
|
{
|
||||||
enet_peer_disconnect_now((ENetPeer*)_peer, 0);
|
enet_peer_disconnect_now((ENetPeer*)peer, 0);
|
||||||
_peerMap.Remove(connectionId);
|
_peerMap.Remove(connectionId);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -276,8 +276,7 @@ void RigidBody::UpdateMass()
|
|||||||
float raiseMassToPower = 0.75f;
|
float raiseMassToPower = 0.75f;
|
||||||
// TODO: link physical material or expose density parameter
|
// TODO: link physical material or expose density parameter
|
||||||
|
|
||||||
PxVec3 centerOfMassOffset = C2P(_centerOfMassOffset);
|
PxRigidBodyExt::updateMassAndInertia(*_actor, densityKGPerCubicUU);
|
||||||
PxRigidBodyExt::updateMassAndInertia(*_actor, densityKGPerCubicUU, ¢erOfMassOffset);
|
|
||||||
|
|
||||||
// Grab old mass so we can apply new mass while maintaining inertia tensor
|
// Grab old mass so we can apply new mass while maintaining inertia tensor
|
||||||
const float oldMass = _actor->getMass();
|
const float oldMass = _actor->getMass();
|
||||||
|
|||||||
@@ -291,7 +291,8 @@ void WheeledVehicle::Setup()
|
|||||||
offsets[i] = C2P(wheel.Collider->GetLocalPosition());
|
offsets[i] = C2P(wheel.Collider->GetLocalPosition());
|
||||||
}
|
}
|
||||||
PxF32 sprungMasses[PX_MAX_NB_WHEELS];
|
PxF32 sprungMasses[PX_MAX_NB_WHEELS];
|
||||||
PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, _actor->getMass(), 1, sprungMasses);
|
const float mass = _actor->getMass();
|
||||||
|
PxVehicleComputeSprungMasses(wheels.Count(), offsets, centerOfMassOffset.p, mass, 1, sprungMasses);
|
||||||
PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
|
PxVehicleWheelsSimData* wheelsSimData = PxVehicleWheelsSimData::allocate(wheels.Count());
|
||||||
for (int32 i = 0; i < wheels.Count(); i++)
|
for (int32 i = 0; i < wheels.Count(); i++)
|
||||||
{
|
{
|
||||||
@@ -303,15 +304,17 @@ void WheeledVehicle::Setup()
|
|||||||
|
|
||||||
PxVehicleSuspensionData suspensionData;
|
PxVehicleSuspensionData suspensionData;
|
||||||
const float suspensionFrequency = 7.0f;
|
const float suspensionFrequency = 7.0f;
|
||||||
const float suspensionDampingRatio = 1.0f;
|
suspensionData.mMaxCompression = wheel.SuspensionMaxRaise;
|
||||||
suspensionData.mMaxCompression = 10.0f;
|
suspensionData.mMaxDroop = wheel.SuspensionMaxDrop;
|
||||||
suspensionData.mMaxDroop = 10.0f;
|
|
||||||
suspensionData.mSprungMass = sprungMasses[i];
|
suspensionData.mSprungMass = sprungMasses[i];
|
||||||
suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass;
|
suspensionData.mSpringStrength = Math::Square(suspensionFrequency) * suspensionData.mSprungMass;
|
||||||
suspensionData.mSpringDamperRate = suspensionDampingRatio * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass);
|
suspensionData.mSpringDamperRate = wheel.SuspensionDampingRate * 2.0f * Math::Sqrt(suspensionData.mSpringStrength * suspensionData.mSprungMass);
|
||||||
|
|
||||||
PxVehicleTireData tire;
|
PxVehicleTireData tire;
|
||||||
tire.mType = 0;
|
tire.mType = 0;
|
||||||
|
tire.mLatStiffX = wheel.TireLateralMax;
|
||||||
|
tire.mLatStiffY = wheel.TireLateralStiffness;
|
||||||
|
tire.mLongitudinalStiffnessPerUnitGravity = wheel.TireLongitudinalStiffness;
|
||||||
|
|
||||||
PxVehicleWheelData wheelData;
|
PxVehicleWheelData wheelData;
|
||||||
wheelData.mMass = wheel.Mass;
|
wheelData.mMass = wheel.Mass;
|
||||||
@@ -324,16 +327,17 @@ void WheeledVehicle::Setup()
|
|||||||
wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque);
|
wheelData.mMaxHandBrakeTorque = M2ToCm2(wheel.MaxHandBrakeTorque);
|
||||||
|
|
||||||
PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]);
|
PxVec3 centreOffset = centerOfMassOffset.transformInv(offsets[i]);
|
||||||
float suspensionForceOffset = 0.0f;
|
PxVec3 forceAppPointOffset(centreOffset.x, wheel.SuspensionForceOffset, centreOffset.z);
|
||||||
PxVec3 forceAppPointOffset(centreOffset.x, centreOffset.y, centreOffset.z + suspensionForceOffset);
|
|
||||||
|
|
||||||
wheelsSimData->setTireData(i, tire);
|
wheelsSimData->setTireData(i, tire);
|
||||||
wheelsSimData->setWheelData(i, wheelData);
|
wheelsSimData->setWheelData(i, wheelData);
|
||||||
wheelsSimData->setSuspensionData(i, suspensionData);
|
wheelsSimData->setSuspensionData(i, suspensionData);
|
||||||
wheelsSimData->setSuspTravelDirection(i, PxVec3(0, -1, 0));
|
wheelsSimData->setSuspTravelDirection(i, centerOfMassOffset.rotate(PxVec3(0.0f, -1.0f, 0.0f)));
|
||||||
wheelsSimData->setWheelCentreOffset(i, centreOffset);
|
wheelsSimData->setWheelCentreOffset(i, centreOffset);
|
||||||
wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset);
|
wheelsSimData->setSuspForceAppPointOffset(i, forceAppPointOffset);
|
||||||
wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset);
|
wheelsSimData->setTireForceAppPointOffset(i, forceAppPointOffset);
|
||||||
|
wheelsSimData->setSubStepCount(4.0f * 100.0f, 3, 1);
|
||||||
|
wheelsSimData->setMinLongSlipDenominator(4.0f * 100.0f);
|
||||||
|
|
||||||
PxShape* wheelShape = wheel.Collider->GetPxShape();
|
PxShape* wheelShape = wheel.Collider->GetPxShape();
|
||||||
if (wheel.Collider->IsActiveInHierarchy())
|
if (wheel.Collider->IsActiveInHierarchy())
|
||||||
@@ -346,6 +350,9 @@ void WheeledVehicle::Setup()
|
|||||||
wheelShape->setQueryFilterData(filter);
|
wheelShape->setQueryFilterData(filter);
|
||||||
wheelShape->setSimulationFilterData(filter);
|
wheelShape->setSimulationFilterData(filter);
|
||||||
wheelsSimData->setSceneQueryFilterData(i, filter);
|
wheelsSimData->setSceneQueryFilterData(i, filter);
|
||||||
|
|
||||||
|
// Remove wheels from the simulation (suspension force hold the vehicle)
|
||||||
|
wheelShape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -508,11 +515,29 @@ void WheeledVehicle::Setup()
|
|||||||
void WheeledVehicle::DrawPhysicsDebug(RenderView& view)
|
void WheeledVehicle::DrawPhysicsDebug(RenderView& view)
|
||||||
{
|
{
|
||||||
// Wheels shapes
|
// Wheels shapes
|
||||||
for (auto& wheel : _wheels)
|
for (auto& data : _wheelsData)
|
||||||
{
|
{
|
||||||
|
int32 wheelIndex = 0;
|
||||||
|
for (; wheelIndex < _wheels.Count(); wheelIndex++)
|
||||||
|
{
|
||||||
|
if (_wheels[wheelIndex].Collider == data.Collider)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (wheelIndex == _wheels.Count())
|
||||||
|
break;
|
||||||
|
auto& wheel = _wheels[wheelIndex];
|
||||||
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
|
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
|
||||||
{
|
{
|
||||||
DEBUG_DRAW_WIRE_CYLINDER(wheel.Collider->GetPosition(), wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true);
|
const Vector3 currentPos = wheel.Collider->GetPosition();
|
||||||
|
const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, true);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, true);
|
||||||
|
DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, true);
|
||||||
|
DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.8f, 0, true);
|
||||||
|
if (!data.State.IsInAir)
|
||||||
|
{
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,11 +545,35 @@ void WheeledVehicle::DrawPhysicsDebug(RenderView& view)
|
|||||||
void WheeledVehicle::OnDebugDrawSelected()
|
void WheeledVehicle::OnDebugDrawSelected()
|
||||||
{
|
{
|
||||||
// Wheels shapes
|
// Wheels shapes
|
||||||
for (auto& wheel : _wheels)
|
for (auto& data : _wheelsData)
|
||||||
{
|
{
|
||||||
|
int32 wheelIndex = 0;
|
||||||
|
for (; wheelIndex < _wheels.Count(); wheelIndex++)
|
||||||
|
{
|
||||||
|
if (_wheels[wheelIndex].Collider == data.Collider)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (wheelIndex == _wheels.Count())
|
||||||
|
break;
|
||||||
|
auto& wheel = _wheels[wheelIndex];
|
||||||
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
|
if (wheel.Collider && wheel.Collider->GetParent() == this && !wheel.Collider->GetIsTrigger())
|
||||||
{
|
{
|
||||||
DEBUG_DRAW_WIRE_CYLINDER(wheel.Collider->GetPosition(), wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false);
|
const Vector3 currentPos = wheel.Collider->GetPosition();
|
||||||
|
const Vector3 basePos = currentPos - Vector3(0, data.State.SuspensionOffset, 0);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(basePos, wheel.Radius * 0.07f), Color::Blue * 0.3f, 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(currentPos, wheel.Radius * 0.08f), Color::Blue * 0.8f, 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(P2C(_actor->getGlobalPose().transform(wheel.Collider->GetPxShape()->getLocalPose()).p), wheel.Radius * 0.11f), Color::OrangeRed * 0.8f, 0, false);
|
||||||
|
DEBUG_DRAW_LINE(basePos, currentPos, Color::Blue, 0, false);
|
||||||
|
DEBUG_DRAW_WIRE_CYLINDER(currentPos, wheel.Collider->GetOrientation(), wheel.Radius, wheel.Width, Color::Red * 0.4f, 0, false);
|
||||||
|
if (!data.State.SuspensionTraceStart.IsZero())
|
||||||
|
{
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.SuspensionTraceStart, 5.0f), Color::AliceBlue, 0, false);
|
||||||
|
DEBUG_DRAW_LINE(data.State.SuspensionTraceStart, data.State.SuspensionTraceEnd, data.State.IsInAir ? Color::Red : Color::Green, 0, false);
|
||||||
|
}
|
||||||
|
if (!data.State.IsInAir)
|
||||||
|
{
|
||||||
|
DEBUG_DRAW_WIRE_SPHERE(BoundingSphere(data.State.TireContactPoint, 5.0f), Color::Green, 0, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -545,6 +594,7 @@ void WheeledVehicle::Serialize(SerializeStream& stream, const void* otherObj)
|
|||||||
SERIALIZE_MEMBER(DriveType, _driveType);
|
SERIALIZE_MEMBER(DriveType, _driveType);
|
||||||
SERIALIZE_MEMBER(Wheels, _wheels);
|
SERIALIZE_MEMBER(Wheels, _wheels);
|
||||||
SERIALIZE(UseReverseAsBrake);
|
SERIALIZE(UseReverseAsBrake);
|
||||||
|
SERIALIZE(UseAnalogSteering);
|
||||||
SERIALIZE_MEMBER(Engine, _engine);
|
SERIALIZE_MEMBER(Engine, _engine);
|
||||||
SERIALIZE_MEMBER(Differential, _differential);
|
SERIALIZE_MEMBER(Differential, _differential);
|
||||||
SERIALIZE_MEMBER(Gearbox, _gearbox);
|
SERIALIZE_MEMBER(Gearbox, _gearbox);
|
||||||
@@ -557,6 +607,7 @@ void WheeledVehicle::Deserialize(DeserializeStream& stream, ISerializeModifier*
|
|||||||
DESERIALIZE_MEMBER(DriveType, _driveType);
|
DESERIALIZE_MEMBER(DriveType, _driveType);
|
||||||
DESERIALIZE_MEMBER(Wheels, _wheels);
|
DESERIALIZE_MEMBER(Wheels, _wheels);
|
||||||
DESERIALIZE(UseReverseAsBrake);
|
DESERIALIZE(UseReverseAsBrake);
|
||||||
|
DESERIALIZE(UseAnalogSteering);
|
||||||
DESERIALIZE_MEMBER(Engine, _engine);
|
DESERIALIZE_MEMBER(Engine, _engine);
|
||||||
DESERIALIZE_MEMBER(Differential, _differential);
|
DESERIALIZE_MEMBER(Differential, _differential);
|
||||||
DESERIALIZE_MEMBER(Gearbox, _gearbox);
|
DESERIALIZE_MEMBER(Gearbox, _gearbox);
|
||||||
|
|||||||
@@ -172,47 +172,82 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wheel placement type.
|
/// Wheel placement type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() WheelTypes Type = WheelTypes::FrontLeft;
|
API_FIELD(Attributes="EditorOrder(0)") WheelTypes Type = WheelTypes::FrontLeft;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Combined mass of the wheel and the tire in kg. Typically, a wheel has mass between 20Kg and 80Kg but can be lower and higher depending on the vehicle.
|
/// Combined mass of the wheel and the tire in kg. Typically, a wheel has mass between 20Kg and 80Kg but can be lower and higher depending on the vehicle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float Mass = 20.0f;
|
API_FIELD(Attributes="EditorOrder(1)") float Mass = 20.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Distance in metres between the center of the wheel and the outside rim of the tire. It is important that the value of the radius closely matches the radius of the render mesh of the wheel. Any mismatch will result in the wheels either hovering above the ground or intersecting the ground.
|
/// Distance in metres between the center of the wheel and the outside rim of the tire. It is important that the value of the radius closely matches the radius of the render mesh of the wheel. Any mismatch will result in the wheels either hovering above the ground or intersecting the ground.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float Radius = 50.0f;
|
API_FIELD(Attributes="EditorOrder(2)") float Radius = 50.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Full width of the wheel in metres. This parameter has no bearing on the handling but is a very useful parameter to have when trying to render debug data relating to the wheel/tire/suspension.
|
/// Full width of the wheel in metres. This parameter has no bearing on the handling but is a very useful parameter to have when trying to render debug data relating to the wheel/tire/suspension.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float Width = 20.0f;
|
API_FIELD(Attributes="EditorOrder(3)") float Width = 20.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Max steer angle that can be achieved by the wheel (in degrees).
|
/// Max steer angle that can be achieved by the wheel (in degrees).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="Limit(0)") float MaxSteerAngle = 0.0f;
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(10)") float MaxSteerAngle = 0.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Damping rate applied to wheel. Specified in kilograms metres-squared per second (kg m^2 s^-1).
|
/// Damping rate applied to wheel. Specified in kilograms metres-squared per second (kg m^2 s^-1).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="Limit(0)") float DampingRate = 0.25f;
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(11)") float DampingRate = 0.25f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Max brake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
|
/// Max brake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="Limit(0)") float MaxBrakeTorque = 1500.0f;
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(12)") float MaxBrakeTorque = 1500.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Max handbrake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
|
/// Max handbrake torque that can be applied to wheel. Specified in kilograms metres-squared per second-squared (kg m^2 s^-2)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD(Attributes="Limit(0)") float MaxHandBrakeTorque = 2000.0f;
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Steering\"), EditorOrder(13)") float MaxHandBrakeTorque = 2000.0f;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Collider that represents the wheel shape and it's placement. Has to be attached as a child to the vehicle. Triangle mesh collider is not supported (use convex mesh or basic shapes).
|
/// Collider that represents the wheel shape and it's placement. Has to be attached as a child to the vehicle. Triangle mesh collider is not supported (use convex mesh or basic shapes).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() ScriptingObjectReference<Collider> Collider;
|
API_FIELD(Attributes="EditorOrder(4)") ScriptingObjectReference<Collider> Collider;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spring damper rate of suspension unit.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(20)") float SuspensionDampingRate = 1.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum offset for the suspension that wheel can go above resting location.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(21)") float SuspensionMaxRaise = 10.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum offset for the suspension that wheel can go below resting location.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="Limit(0), EditorDisplay(\"Suspension\"), EditorOrder(22)") float SuspensionMaxDrop = 10.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The vertical offset from where suspension forces are applied (relative to the vehicle center of mass). The suspension force is applies on the vertical axis going though the wheel center.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorDisplay(\"Suspension\"), EditorOrder(23)") float SuspensionForceOffset = 0.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tire lateral stiffness to have given lateral slip.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorDisplay(\"Tire\"), EditorOrder(30)") float TireLateralStiffness = 17.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The maximum tire load (normalized) at which tire cannot provide more lateral stiffness (no matter how much extra load is applied to it).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorDisplay(\"Tire\"), EditorOrder(31)") float TireLateralMax = 2.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tire longitudinal stiffness to have given longitudinal slip.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorDisplay(\"Tire\"), EditorOrder(32)") float TireLongitudinalStiffness = 1000.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -246,6 +281,33 @@ public:
|
|||||||
/// The friction experienced by the tire for the combination of tire type and surface type after accounting.
|
/// The friction experienced by the tire for the combination of tire type and surface type after accounting.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() float TireFriction = 0.0f;
|
API_FIELD() float TireFriction = 0.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The steer angle (in degrees) of the wheel about the "up" vector accounting for input steer and toe and, if applicable, Ackermann steer correction.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() float SteerAngle = 0.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The rotation angle (in degrees) about the rolling axis for the specified wheel.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() float RotationAngle = 0.0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The compression of the suspension spring. Offsets the wheel location.
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() float SuspensionOffset = 0.0f;
|
||||||
|
|
||||||
|
#if USE_EDITOR
|
||||||
|
/// <summary>
|
||||||
|
/// The start location of the suspension raycast start (Editor only for debugging).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() Vector3 SuspensionTraceStart = Vector3::Zero;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The start location of the suspension raycast end (Editor only for debugging).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD() Vector3 SuspensionTraceEnd = Vector3::Zero;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -274,6 +336,12 @@ public:
|
|||||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Vehicle\")")
|
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"Vehicle\")")
|
||||||
bool UseReverseAsBrake = true;
|
bool UseReverseAsBrake = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// If checked, the vehicle driving and steering inputs will be used as analog values (from gamepad), otherwise will be used as digital input (from keyboard).
|
||||||
|
/// </summary>
|
||||||
|
API_FIELD(Attributes="EditorOrder(1), EditorDisplay(\"Vehicle\")")
|
||||||
|
bool UseAnalogSteering = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the vehicle driving model type.
|
/// Gets the vehicle driving model type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -105,7 +105,14 @@ void CharacterController::SetStepOffset(float value)
|
|||||||
_stepOffset = value;
|
_stepOffset = value;
|
||||||
|
|
||||||
if (_controller)
|
if (_controller)
|
||||||
_controller->setStepOffset(value);
|
{
|
||||||
|
const float scaling = _cachedScale.GetAbsolute().MaxValue();
|
||||||
|
const float contactOffset = Math::Max(_contactOffset, ZeroTolerance);
|
||||||
|
const float minSize = 0.001f;
|
||||||
|
const float height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||||
|
const float radius = Math::Max(Math::Abs(_radius) * scaling - contactOffset, minSize);
|
||||||
|
_controller->setStepOffset(Math::Min(value, height + radius * 2.0f - minSize));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CharacterController::SetUpDirection(const Vector3& up)
|
void CharacterController::SetUpDirection(const Vector3& up)
|
||||||
@@ -223,7 +230,6 @@ void CharacterController::CreateController()
|
|||||||
desc.slopeLimit = Math::Cos(_slopeLimit * DegreesToRadians);
|
desc.slopeLimit = Math::Cos(_slopeLimit * DegreesToRadians);
|
||||||
desc.nonWalkableMode = static_cast<PxControllerNonWalkableMode::Enum>(_nonWalkableMode);
|
desc.nonWalkableMode = static_cast<PxControllerNonWalkableMode::Enum>(_nonWalkableMode);
|
||||||
desc.climbingMode = PxCapsuleClimbingMode::eEASY;
|
desc.climbingMode = PxCapsuleClimbingMode::eEASY;
|
||||||
desc.stepOffset = _stepOffset;
|
|
||||||
if (Material && !Material->WaitForLoaded())
|
if (Material && !Material->WaitForLoaded())
|
||||||
desc.material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial();
|
desc.material = ((PhysicalMaterial*)Material->Instance)->GetPhysXMaterial();
|
||||||
else
|
else
|
||||||
@@ -233,6 +239,7 @@ void CharacterController::CreateController()
|
|||||||
const float minSize = 0.001f;
|
const float minSize = 0.001f;
|
||||||
desc.height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
desc.height = Math::Max(Math::Abs(_height) * scaling, minSize);
|
||||||
desc.radius = Math::Max(Math::Abs(_radius) * scaling - desc.contactOffset, minSize);
|
desc.radius = Math::Max(Math::Abs(_radius) * scaling - desc.contactOffset, minSize);
|
||||||
|
desc.stepOffset = Math::Min(_stepOffset, desc.height + desc.radius * 2.0f - minSize);
|
||||||
|
|
||||||
// Create controller
|
// Create controller
|
||||||
_controller = (PxCapsuleController*)Physics::GetControllerManager()->createController(desc);
|
_controller = (PxCapsuleController*)Physics::GetControllerManager()->createController(desc);
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output)
|
bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& output)
|
||||||
{
|
{
|
||||||
ENSURE_CAN_COOK;
|
ENSURE_CAN_COOK;
|
||||||
|
if (input.VertexCount == 0)
|
||||||
|
LOG(Warning, "Empty mesh data for collision cooking.");
|
||||||
|
|
||||||
// Init options
|
// Init options
|
||||||
PxConvexMeshDesc desc;
|
PxConvexMeshDesc desc;
|
||||||
@@ -62,6 +64,8 @@ bool CollisionCooking::CookConvexMesh(CookingInput& input, BytesContainer& outpu
|
|||||||
bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output)
|
bool CollisionCooking::CookTriangleMesh(CookingInput& input, BytesContainer& output)
|
||||||
{
|
{
|
||||||
ENSURE_CAN_COOK;
|
ENSURE_CAN_COOK;
|
||||||
|
if (input.VertexCount == 0 || input.IndexCount == 0)
|
||||||
|
LOG(Warning, "Empty mesh data for collision cooking.");
|
||||||
|
|
||||||
// Init options
|
// Init options
|
||||||
PxTriangleMeshDesc desc;
|
PxTriangleMeshDesc desc;
|
||||||
@@ -274,11 +278,11 @@ bool CollisionCooking::CookCollision(const Argument& arg, CollisionData::Seriali
|
|||||||
// Combine meshes into one
|
// Combine meshes into one
|
||||||
int32 vCount = 0;
|
int32 vCount = 0;
|
||||||
for (int32 i = 0; i < vertexCounts.Count(); i++)
|
for (int32 i = 0; i < vertexCounts.Count(); i++)
|
||||||
vCount += vertexCounts[0];
|
vCount += vertexCounts[i];
|
||||||
finalVertexData.Allocate(vCount);
|
finalVertexData.Allocate(vCount);
|
||||||
int32 iCount = 0;
|
int32 iCount = 0;
|
||||||
for (int32 i = 0; i < indexCounts.Count(); i++)
|
for (int32 i = 0; i < indexCounts.Count(); i++)
|
||||||
iCount += indexCounts[0];
|
iCount += indexCounts[i];
|
||||||
finalIndexData.Allocate(iCount);
|
finalIndexData.Allocate(iCount);
|
||||||
int32 vertexCounter = 0, indexCounter = 0;
|
int32 vertexCounter = 0, indexCounter = 0;
|
||||||
for (int32 i = 0; i < meshesCount; i++)
|
for (int32 i = 0; i < meshesCount; i++)
|
||||||
|
|||||||
@@ -31,6 +31,12 @@
|
|||||||
// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned.
|
// Temporary memory size used by the PhysX during the simulation. Must be multiply of 4kB and 16bit aligned.
|
||||||
#define SCRATCH_BLOCK_SIZE (1024 * 128)
|
#define SCRATCH_BLOCK_SIZE (1024 * 128)
|
||||||
|
|
||||||
|
#define PHYSX_VEHICLE_DEBUG_TELEMETRY 0
|
||||||
|
|
||||||
|
#if PHYSX_VEHICLE_DEBUG_TELEMETRY
|
||||||
|
#include "Engine/Core/Utilities.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
class PhysXAllocator : public PxAllocatorCallback
|
class PhysXAllocator : public PxAllocatorCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -661,6 +667,8 @@ void Physics::CollectResults()
|
|||||||
int32 wheelsCount = 0;
|
int32 wheelsCount = 0;
|
||||||
for (auto wheelVehicle : WheelVehicles)
|
for (auto wheelVehicle : WheelVehicles)
|
||||||
{
|
{
|
||||||
|
if (!wheelVehicle->IsActiveInHierarchy())
|
||||||
|
continue;
|
||||||
auto drive = (PxVehicleWheels*)wheelVehicle->_drive;
|
auto drive = (PxVehicleWheels*)wheelVehicle->_drive;
|
||||||
ASSERT(drive);
|
ASSERT(drive);
|
||||||
WheelVehiclesCache.Add(drive);
|
WheelVehiclesCache.Add(drive);
|
||||||
@@ -742,6 +750,23 @@ void Physics::CollectResults()
|
|||||||
5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT
|
5.0f, // fall rate eANALOG_INPUT_STEER_RIGHT
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
PxVehicleKeySmoothingData keySmoothing =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
3.0f, // rise rate eANALOG_INPUT_ACCEL
|
||||||
|
3.0f, // rise rate eANALOG_INPUT_BRAKE
|
||||||
|
10.0f, // rise rate eANALOG_INPUT_HANDBRAKE
|
||||||
|
2.5f, // rise rate eANALOG_INPUT_STEER_LEFT
|
||||||
|
2.5f, // rise rate eANALOG_INPUT_STEER_RIGHT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
5.0f, // fall rate eANALOG_INPUT__ACCEL
|
||||||
|
5.0f, // fall rate eANALOG_INPUT__BRAKE
|
||||||
|
10.0f, // fall rate eANALOG_INPUT__HANDBRAKE
|
||||||
|
5.0f, // fall rate eANALOG_INPUT_STEER_LEFT
|
||||||
|
5.0f // fall rate eANALOG_INPUT_STEER_RIGHT
|
||||||
|
}
|
||||||
|
};
|
||||||
// Reference: PhysX SDK docs
|
// Reference: PhysX SDK docs
|
||||||
// TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range)
|
// TODO: expose steer vs forward curve into per-vehicle (up to 8 points, values clamped into 0/1 range)
|
||||||
static constexpr PxF32 steerVsForwardSpeedData[] =
|
static constexpr PxF32 steerVsForwardSpeedData[] =
|
||||||
@@ -757,28 +782,60 @@ void Physics::CollectResults()
|
|||||||
};
|
};
|
||||||
const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
|
const PxFixedSizeLookupTable<8> steerVsForwardSpeed(steerVsForwardSpeedData, 4);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
switch (wheelVehicle->_driveTypeCurrent)
|
if (wheelVehicle->UseAnalogSteering)
|
||||||
{
|
{
|
||||||
case WheeledVehicle::DriveTypes::Drive4W:
|
switch (wheelVehicle->_driveTypeCurrent)
|
||||||
{
|
{
|
||||||
PxVehicleDrive4WRawInputData rawInputData;
|
case WheeledVehicle::DriveTypes::Drive4W:
|
||||||
rawInputData.setAnalogAccel(throttle);
|
{
|
||||||
rawInputData.setAnalogBrake(brake);
|
PxVehicleDrive4WRawInputData rawInputData;
|
||||||
rawInputData.setAnalogSteer(wheelVehicle->_steering);
|
rawInputData.setAnalogAccel(throttle);
|
||||||
rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
|
rawInputData.setAnalogBrake(brake);
|
||||||
PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDrive4W*)drive);
|
rawInputData.setAnalogSteer(wheelVehicle->_steering);
|
||||||
break;
|
rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
|
||||||
|
PxVehicleDrive4WSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDrive4W*)drive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WheeledVehicle::DriveTypes::DriveNW:
|
||||||
|
{
|
||||||
|
PxVehicleDriveNWRawInputData rawInputData;
|
||||||
|
rawInputData.setAnalogAccel(throttle);
|
||||||
|
rawInputData.setAnalogBrake(brake);
|
||||||
|
rawInputData.setAnalogSteer(wheelVehicle->_steering);
|
||||||
|
rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
|
||||||
|
PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDriveNW*)drive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case WheeledVehicle::DriveTypes::DriveNW:
|
else
|
||||||
{
|
{
|
||||||
PxVehicleDriveNWRawInputData rawInputData;
|
const float deadZone = 0.1f;
|
||||||
rawInputData.setAnalogAccel(throttle);
|
switch (wheelVehicle->_driveTypeCurrent)
|
||||||
rawInputData.setAnalogBrake(brake);
|
{
|
||||||
rawInputData.setAnalogSteer(wheelVehicle->_steering);
|
case WheeledVehicle::DriveTypes::Drive4W:
|
||||||
rawInputData.setAnalogHandbrake(wheelVehicle->_handBrake);
|
{
|
||||||
PxVehicleDriveNWSmoothAnalogRawInputsAndSetAnalogInputs(padSmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDriveNW*)drive);
|
PxVehicleDrive4WRawInputData rawInputData;
|
||||||
break;
|
rawInputData.setDigitalAccel(throttle > deadZone);
|
||||||
}
|
rawInputData.setDigitalBrake(brake > deadZone);
|
||||||
|
rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
|
||||||
|
rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
|
||||||
|
rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
|
||||||
|
PxVehicleDrive4WSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDrive4W*)drive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WheeledVehicle::DriveTypes::DriveNW:
|
||||||
|
{
|
||||||
|
PxVehicleDriveNWRawInputData rawInputData;
|
||||||
|
rawInputData.setDigitalAccel(throttle > deadZone);
|
||||||
|
rawInputData.setDigitalBrake(brake > deadZone);
|
||||||
|
rawInputData.setDigitalSteerLeft(wheelVehicle->_steering < -deadZone);
|
||||||
|
rawInputData.setDigitalSteerRight(wheelVehicle->_steering > deadZone);
|
||||||
|
rawInputData.setDigitalHandbrake(wheelVehicle->_handBrake > deadZone);
|
||||||
|
PxVehicleDriveNWSmoothDigitalRawInputsAndSetAnalogInputs(keySmoothing, steerVsForwardSpeed, rawInputData, LastDeltaTime, false, *(PxVehicleDriveNW*)drive);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -787,8 +844,8 @@ void Physics::CollectResults()
|
|||||||
{
|
{
|
||||||
if (WheelRaycastBatchQuery)
|
if (WheelRaycastBatchQuery)
|
||||||
WheelRaycastBatchQuery->release();
|
WheelRaycastBatchQuery->release();
|
||||||
WheelQueryResults.Resize(wheelsCount);
|
WheelQueryResults.Resize(wheelsCount, false);
|
||||||
WheelQueryResults.Resize(WheelQueryResults.Capacity());
|
WheelHitResults.Resize(wheelsCount, false);
|
||||||
PxBatchQueryDesc desc(wheelsCount, 0, 0);
|
PxBatchQueryDesc desc(wheelsCount, 0, 0);
|
||||||
desc.queryMemory.userRaycastResultBuffer = WheelQueryResults.Get();
|
desc.queryMemory.userRaycastResultBuffer = WheelQueryResults.Get();
|
||||||
desc.queryMemory.userRaycastTouchBuffer = WheelHitResults.Get();
|
desc.queryMemory.userRaycastTouchBuffer = WheelHitResults.Get();
|
||||||
@@ -810,13 +867,17 @@ void Physics::CollectResults()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Setup cache for wheel states
|
// Setup cache for wheel states
|
||||||
WheelVehiclesResultsPerVehicle.Resize(WheelVehicles.Count(), false);
|
WheelVehiclesResultsPerVehicle.Resize(WheelVehiclesCache.Count(), false);
|
||||||
WheelVehiclesResultsPerWheel.Resize(wheelsCount, false);
|
WheelVehiclesResultsPerWheel.Resize(wheelsCount, false);
|
||||||
wheelsCount = 0;
|
wheelsCount = 0;
|
||||||
for (int32 i = 0; i < WheelVehicles.Count(); i++)
|
for (int32 i = 0, ii = 0; i < WheelVehicles.Count(); i++)
|
||||||
{
|
{
|
||||||
auto drive = (PxVehicleWheels*)WheelVehicles[i]->_drive;
|
auto wheelVehicle = WheelVehicles[i];
|
||||||
auto& perVehicle = WheelVehiclesResultsPerVehicle[i];
|
if (!wheelVehicle->IsActiveInHierarchy())
|
||||||
|
continue;
|
||||||
|
auto drive = (PxVehicleWheels*)WheelVehicles[ii]->_drive;
|
||||||
|
auto& perVehicle = WheelVehiclesResultsPerVehicle[ii];
|
||||||
|
ii++;
|
||||||
perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels();
|
perVehicle.nbWheelQueryResults = drive->mWheelsSimData.getNbWheels();
|
||||||
perVehicle.wheelQueryResults = WheelVehiclesResultsPerWheel.Get() + wheelsCount;
|
perVehicle.wheelQueryResults = WheelVehiclesResultsPerWheel.Get() + wheelsCount;
|
||||||
wheelsCount += perVehicle.nbWheelQueryResults;
|
wheelsCount += perVehicle.nbWheelQueryResults;
|
||||||
@@ -827,17 +888,26 @@ void Physics::CollectResults()
|
|||||||
PxVehicleUpdates(LastDeltaTime, PhysicsScene->getGravity(), *WheelTireFrictions, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelVehiclesResultsPerVehicle.Get());
|
PxVehicleUpdates(LastDeltaTime, PhysicsScene->getGravity(), *WheelTireFrictions, WheelVehiclesCache.Count(), WheelVehiclesCache.Get(), WheelVehiclesResultsPerVehicle.Get());
|
||||||
|
|
||||||
// Synchronize state
|
// Synchronize state
|
||||||
for (int32 i = 0; i < WheelVehicles.Count(); i++)
|
for (int32 i = 0, ii = 0; i < WheelVehicles.Count(); i++)
|
||||||
{
|
{
|
||||||
auto wheelVehicle = WheelVehicles[i];
|
auto wheelVehicle = WheelVehicles[i];
|
||||||
auto drive = WheelVehiclesCache[i];
|
if (!wheelVehicle->IsActiveInHierarchy())
|
||||||
auto& perVehicle = WheelVehiclesResultsPerVehicle[i];
|
continue;
|
||||||
|
auto drive = WheelVehiclesCache[ii];
|
||||||
|
auto& perVehicle = WheelVehiclesResultsPerVehicle[ii];
|
||||||
|
ii++;
|
||||||
|
#if PHYSX_VEHICLE_DEBUG_TELEMETRY
|
||||||
|
LOG(Info, "Vehicle[{}] Gear={}, RPM={}", ii, wheelVehicle->GetCurrentGear(), (int32)wheelVehicle->GetEngineRotationSpeed());
|
||||||
|
#endif
|
||||||
|
|
||||||
// Update wheels
|
// Update wheels
|
||||||
for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++)
|
for (int32 j = 0; j < wheelVehicle->_wheelsData.Count(); j++)
|
||||||
{
|
{
|
||||||
auto& wheelData = wheelVehicle->_wheelsData[j];
|
auto& wheelData = wheelVehicle->_wheelsData[j];
|
||||||
auto& perWheel = perVehicle.wheelQueryResults[j];
|
auto& perWheel = perVehicle.wheelQueryResults[j];
|
||||||
|
#if PHYSX_VEHICLE_DEBUG_TELEMETRY
|
||||||
|
LOG(Info, "Vehicle[{}] Wheel[{}] longitudinalSlip={}, lateralSlip={}, suspSpringForce={}", ii, j, Utilities::RoundTo2DecimalPlaces(perWheel.longitudinalSlip), Utilities::RoundTo2DecimalPlaces(perWheel.lateralSlip), (int32)perWheel.suspSpringForce);
|
||||||
|
#endif
|
||||||
|
|
||||||
auto& state = wheelData.State;
|
auto& state = wheelData.State;
|
||||||
state.IsInAir = perWheel.isInAir;
|
state.IsInAir = perWheel.isInAir;
|
||||||
@@ -845,10 +915,24 @@ void Physics::CollectResults()
|
|||||||
state.TireContactPoint = P2C(perWheel.tireContactPoint);
|
state.TireContactPoint = P2C(perWheel.tireContactPoint);
|
||||||
state.TireContactNormal = P2C(perWheel.tireContactNormal);
|
state.TireContactNormal = P2C(perWheel.tireContactNormal);
|
||||||
state.TireFriction = perWheel.tireFriction;
|
state.TireFriction = perWheel.tireFriction;
|
||||||
|
state.SteerAngle = RadiansToDegrees * perWheel.steerAngle;
|
||||||
|
state.RotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j);
|
||||||
|
state.SuspensionOffset = perWheel.suspJounce;
|
||||||
|
#if USE_EDITOR
|
||||||
|
state.SuspensionTraceStart = P2C(perWheel.suspLineStart);
|
||||||
|
state.SuspensionTraceEnd = P2C(perWheel.suspLineStart + perWheel.suspLineDir * perWheel.suspLineLength);
|
||||||
|
#endif
|
||||||
|
|
||||||
const float wheelRotationAngle = -RadiansToDegrees * drive->mWheelsDynData.getWheelRotationAngle(j);
|
if (!wheelData.Collider)
|
||||||
const float wheelSteerAngle = RadiansToDegrees * perWheel.steerAngle;
|
continue;
|
||||||
wheelData.Collider->SetLocalOrientation(Quaternion::Euler(0, wheelSteerAngle, wheelRotationAngle) * wheelData.LocalOrientation);
|
auto shape = wheelData.Collider->GetPxShape();
|
||||||
|
|
||||||
|
// Update wheel collider transformation
|
||||||
|
auto localPose = shape->getLocalPose();
|
||||||
|
Transform t = wheelData.Collider->GetLocalTransform();
|
||||||
|
t.Orientation = Quaternion::Euler(0, state.SteerAngle, state.RotationAngle) * wheelData.LocalOrientation;
|
||||||
|
t.Translation = P2C(localPose.p) / wheelVehicle->GetScale() - t.Orientation * wheelData.Collider->GetCenter();
|
||||||
|
wheelData.Collider->SetLocalTransform(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ DECLARE_SCRIPTING_TYPE_MINIMAL(CreateWindowSettings);
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum size.
|
/// The maximum size.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FIELD() Vector2 MaximumSize = Vector2(4096, 4096);
|
API_FIELD() Vector2 MaximumSize = Vector2(8192, 4096);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The start position mode.
|
/// The start position mode.
|
||||||
|
|||||||
@@ -386,33 +386,31 @@ struct TIsPODType<ProfilerCPU::Event>
|
|||||||
enum { Value = true };
|
enum { Value = true };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#include "ProfilerSrcLoc.h"
|
||||||
|
|
||||||
// Shortcut macros for profiling a single code block execution on CPU
|
// Shortcut macros for profiling a single code block execution on CPU
|
||||||
// Use ZoneTransient for Tracy for code that can be hot-reloaded (eg. in Editor) or if name can be a variable
|
// Use ZoneTransient for Tracy for code that can be hot-reloaded (eg. in Editor) or if name can be a variable
|
||||||
|
#define PROFILE_CPU_USE_TRANSIENT_DATA 0
|
||||||
|
|
||||||
#define PROFILE_CPU_NAMED(name) ZoneTransientN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(name)
|
#if PROFILE_CPU_USE_TRANSIENT_DATA
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
|
|
||||||
#if USE_EDITOR
|
|
||||||
#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__))
|
|
||||||
#else
|
|
||||||
#define PROFILE_CPU() ZoneNamed(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(TEXT(__FUNCTION__))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#if USE_EDITOR
|
|
||||||
#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(__FUNCTION__)
|
#define PROFILE_CPU() ZoneTransient(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(__FUNCTION__)
|
||||||
|
#define PROFILE_CPU_NAMED(name) ZoneTransientN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(name)
|
||||||
#else
|
#else
|
||||||
#define PROFILE_CPU() ZoneNamed(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(__FUNCTION__)
|
#define PROFILE_CPU() ZoneNamed(___tracy_scoped_zone, true); ScopeProfileBlockCPU ProfileBlockCPU(__FUNCTION__)
|
||||||
|
#define PROFILE_CPU_NAMED(name) ZoneNamedN(___tracy_scoped_zone, name, true); ScopeProfileBlockCPU ProfileBlockCPU(name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef TRACY_ENABLE
|
||||||
|
#define PROFILE_CPU_SRC_LOC(srcLoc) tracy::ScopedZone ___tracy_scoped_zone( (tracy::SourceLocationData*)&(srcLoc) ); ScopeProfileBlockCPU ProfileBlockCPU((srcLoc).name)
|
||||||
|
#else
|
||||||
|
#define PROFILE_CPU_SRC_LOC(srcLoc) ScopeProfileBlockCPU ProfileBlockCPU((srcLoc).name)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Empty macros for disabled profiler
|
// Empty macros for disabled profiler
|
||||||
#define PROFILE_CPU_NAMED(name)
|
|
||||||
#define PROFILE_CPU()
|
#define PROFILE_CPU()
|
||||||
|
#define PROFILE_CPU_NAMED(name)
|
||||||
|
#define PROFILE_CPU_SRC_LOC(srcLoc)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
|
||||||
|
#include "Engine/Core/Types/BaseTypes.h"
|
||||||
|
|
||||||
|
struct FLAXENGINE_API SourceLocationData
|
||||||
|
{
|
||||||
|
const char* name;
|
||||||
|
const char* function;
|
||||||
|
const char* file;
|
||||||
|
uint32 line;
|
||||||
|
uint32 color;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -492,6 +492,7 @@ ScriptingObject* ManagedBinaryModule::ManagedObjectSpawn(const ScriptingObjectSp
|
|||||||
ScriptingObject* object = nativeTypePtr->Script.Spawn(params);
|
ScriptingObject* object = nativeTypePtr->Script.Spawn(params);
|
||||||
if (!object)
|
if (!object)
|
||||||
{
|
{
|
||||||
|
LOG(Error, "Failed to spawn object of type {0} with native base type {1}.", managedTypePtr->ToString(), nativeTypePtr->ToString());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,18 +60,23 @@ MMethod::MMethod(MonoMethod* monoMethod, const char* name, MClass* parentClass)
|
|||||||
ProfilerName.Get()[className.Length()] = ':';
|
ProfilerName.Get()[className.Length()] = ':';
|
||||||
ProfilerName.Get()[className.Length() + 1] = ':';
|
ProfilerName.Get()[className.Length() + 1] = ':';
|
||||||
Platform::MemoryCopy(ProfilerName.Get() + className.Length() + 2, _name.Get(), _name.Length());
|
Platform::MemoryCopy(ProfilerName.Get() + className.Length() + 2, _name.Get(), _name.Length());
|
||||||
|
ProfilerData.name = ProfilerName.Get();
|
||||||
|
ProfilerData.function = _name.Get();
|
||||||
|
ProfilerData.file = nullptr;
|
||||||
|
ProfilerData.line = 0;
|
||||||
|
ProfilerData.color = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject* MMethod::Invoke(void* instance, void** params, MonoObject** exception) const
|
MonoObject* MMethod::Invoke(void* instance, void** params, MonoObject** exception) const
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED(*ProfilerName);
|
PROFILE_CPU_SRC_LOC(ProfilerData);
|
||||||
return mono_runtime_invoke(_monoMethod, instance, params, exception);
|
return mono_runtime_invoke(_monoMethod, instance, params, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
MonoObject* MMethod::InvokeVirtual(MonoObject* instance, void** params, MonoObject** exception) const
|
MonoObject* MMethod::InvokeVirtual(MonoObject* instance, void** params, MonoObject** exception) const
|
||||||
{
|
{
|
||||||
PROFILE_CPU_NAMED(*ProfilerName);
|
PROFILE_CPU_SRC_LOC(ProfilerData);
|
||||||
MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod);
|
MonoMethod* virtualMethod = mono_object_get_virtual_method(instance, _monoMethod);
|
||||||
return mono_runtime_invoke(virtualMethod, instance, params, exception);
|
return mono_runtime_invoke(virtualMethod, instance, params, exception);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
|
#if COMPILE_WITH_PROFILER
|
||||||
|
#include "Engine/Profiler/ProfilerSrcLoc.h"
|
||||||
|
#endif
|
||||||
#include "MTypes.h"
|
#include "MTypes.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -42,6 +45,7 @@ public:
|
|||||||
|
|
||||||
#if COMPILE_WITH_PROFILER
|
#if COMPILE_WITH_PROFILER
|
||||||
MString ProfilerName;
|
MString ProfilerName;
|
||||||
|
SourceLocationData ProfilerData;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if USE_MONO
|
#if USE_MONO
|
||||||
|
|||||||
@@ -9,13 +9,29 @@
|
|||||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||||
#include "Engine/Core/ObjectsRemovalService.h"
|
#include "Engine/Core/ObjectsRemovalService.h"
|
||||||
#include "Engine/Profiler/Profiler.h"
|
#include "Engine/Profiler/Profiler.h"
|
||||||
|
#if TRACY_ENABLE && !PROFILE_CPU_USE_TRANSIENT_DATA
|
||||||
|
#include "Engine/Core/Collections/ChunkedArray.h"
|
||||||
|
#endif
|
||||||
|
#include "Engine/Core/Types/Pair.h"
|
||||||
#include "Engine/Threading/Threading.h"
|
#include "Engine/Threading/Threading.h"
|
||||||
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
|
#include <ThirdParty/mono-2.0/mono/metadata/mono-gc.h>
|
||||||
|
|
||||||
namespace ProfilerInternal
|
namespace ProfilerInternal
|
||||||
{
|
{
|
||||||
#if COMPILE_WITH_PROFILER
|
#if COMPILE_WITH_PROFILER
|
||||||
Array<int32> ManagedEventsGPU;
|
Array<int32, InlinedAllocation<32>> ManagedEventsGPU;
|
||||||
|
#if TRACY_ENABLE && !PROFILE_CPU_USE_TRANSIENT_DATA
|
||||||
|
CriticalSection ManagedSourceLocationsLocker;
|
||||||
|
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
|
String Name;
|
||||||
|
StringAnsi NameAnsi;
|
||||||
|
tracy::SourceLocationData SrcLocation;
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkedArray<Location, 256> ManagedSourceLocations;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void BeginEvent(MonoString* nameObj)
|
void BeginEvent(MonoString* nameObj)
|
||||||
@@ -24,7 +40,34 @@ namespace ProfilerInternal
|
|||||||
const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj));
|
const StringView name((const Char*)mono_string_chars(nameObj), mono_string_length(nameObj));
|
||||||
ProfilerCPU::BeginEvent(*name);
|
ProfilerCPU::BeginEvent(*name);
|
||||||
#if TRACY_ENABLE
|
#if TRACY_ENABLE
|
||||||
|
#if PROFILE_CPU_USE_TRANSIENT_DATA
|
||||||
tracy::ScopedZone::Begin(__LINE__, __FILE__, strlen( __FILE__ ), __FUNCTION__, strlen( __FUNCTION__ ), name.Get(), name.Length() );
|
tracy::ScopedZone::Begin(__LINE__, __FILE__, strlen( __FILE__ ), __FUNCTION__, strlen( __FUNCTION__ ), name.Get(), name.Length() );
|
||||||
|
#else
|
||||||
|
ScopeLock lock(ManagedSourceLocationsLocker);
|
||||||
|
tracy::SourceLocationData* srcLoc = nullptr;
|
||||||
|
for (auto e = ManagedSourceLocations.Begin(); e.IsNotEnd(); ++e)
|
||||||
|
{
|
||||||
|
if (name == e->Name)
|
||||||
|
{
|
||||||
|
srcLoc = &e->SrcLocation;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!srcLoc)
|
||||||
|
{
|
||||||
|
auto& e = ManagedSourceLocations.AddOne();
|
||||||
|
e.Name = name;
|
||||||
|
e.NameAnsi = name.Get();
|
||||||
|
srcLoc = &e.SrcLocation;
|
||||||
|
srcLoc->name = e.NameAnsi.Get();
|
||||||
|
srcLoc->function = nullptr;
|
||||||
|
srcLoc->file = nullptr;
|
||||||
|
srcLoc->line = 0;
|
||||||
|
srcLoc->color = 0;
|
||||||
|
}
|
||||||
|
//static constexpr tracy::SourceLocationData tracySrcLoc{ nullptr, __FUNCTION__, __FILE__, (uint32_t)__LINE__, 0 };
|
||||||
|
tracy::ScopedZone::Begin(srcLoc);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -212,6 +212,7 @@ namespace FlaxEngine.Json
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JsonToken.Comment: break;
|
case JsonToken.Comment: break;
|
||||||
|
case JsonToken.String: break;
|
||||||
default: return value;
|
default: return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,16 +245,21 @@ namespace FlaxEngine.Json
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, object value, Newtonsoft.Json.JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
|
#if FLAX_EDITOR
|
||||||
|
bool writeTypename = (serializer.TypeNameHandling & TypeNameHandling.Objects) == TypeNameHandling.Objects;
|
||||||
|
#else
|
||||||
|
bool writeTypename = false;
|
||||||
|
#endif
|
||||||
var str = (LocalizedString)value;
|
var str = (LocalizedString)value;
|
||||||
if (string.IsNullOrEmpty(str.Id))
|
if (string.IsNullOrEmpty(str.Id) && !writeTypename)
|
||||||
{
|
{
|
||||||
writer.WriteValue(str.Value);
|
writer.WriteValue(str.Value ?? string.Empty);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
#if FLAX_EDITOR
|
#if FLAX_EDITOR
|
||||||
if ((serializer.TypeNameHandling & TypeNameHandling.Objects) == TypeNameHandling.Objects)
|
if (writeTypename)
|
||||||
{
|
{
|
||||||
writer.WritePropertyName("$type");
|
writer.WritePropertyName("$type");
|
||||||
writer.WriteValue("FlaxEngine.LocalizedString, FlaxEngine.CSharp");
|
writer.WriteValue("FlaxEngine.LocalizedString, FlaxEngine.CSharp");
|
||||||
@@ -297,10 +303,15 @@ namespace FlaxEngine.Json
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JsonToken.Comment: break;
|
case JsonToken.Comment: break;
|
||||||
|
case JsonToken.String: break;
|
||||||
default: return str;
|
default: return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
if (existingValue == null && str.Id == null && str.Value == null)
|
||||||
|
return null;
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -134,9 +134,13 @@ void JobSystemService::Dispose()
|
|||||||
|
|
||||||
for (int32 i = 0; i < ThreadsCount; i++)
|
for (int32 i = 0; i < ThreadsCount; i++)
|
||||||
{
|
{
|
||||||
if (Threads[i] && Threads[i]->IsRunning())
|
if (Threads[i])
|
||||||
Threads[i]->Kill(true);
|
{
|
||||||
Threads[i] = nullptr;
|
if (Threads[i]->IsRunning())
|
||||||
|
Threads[i]->Kill(true);
|
||||||
|
Delete(Threads[i]);
|
||||||
|
Threads[i] = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,6 +140,7 @@ namespace FlaxEngine.GUI
|
|||||||
{
|
{
|
||||||
_targetValue = value;
|
_targetValue = value;
|
||||||
_value = value;
|
_value = value;
|
||||||
|
SetUpdate(ref _update, null);
|
||||||
OnValueChanged();
|
OnValueChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
[assembly: Guid("b8442186-4a70-7c85-704a-857c262d00f6")]
|
[assembly: Guid("b8442186-4a70-7c85-704a-857c262d00f6")]
|
||||||
[assembly: AssemblyVersion("1.2.6222")]
|
[assembly: AssemblyVersion("1.2.6224")]
|
||||||
[assembly: AssemblyFileVersion("1.2.6222")]
|
[assembly: AssemblyFileVersion("1.2.6224")]
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define FLAXENGINE_NAME "FlaxEngine"
|
#define FLAXENGINE_NAME "FlaxEngine"
|
||||||
#define FLAXENGINE_VERSION Version(1, 2, 6222)
|
#define FLAXENGINE_VERSION Version(1, 2, 6224)
|
||||||
#define FLAXENGINE_VERSION_TEXT "1.2.6222"
|
#define FLAXENGINE_VERSION_TEXT "1.2.6224"
|
||||||
#define FLAXENGINE_VERSION_MAJOR 1
|
#define FLAXENGINE_VERSION_MAJOR 1
|
||||||
#define FLAXENGINE_VERSION_MINOR 2
|
#define FLAXENGINE_VERSION_MINOR 2
|
||||||
#define FLAXENGINE_VERSION_BUILD 6222
|
#define FLAXENGINE_VERSION_BUILD 6224
|
||||||
#define FLAXENGINE_COMPANY "Flax"
|
#define FLAXENGINE_COMPANY "Flax"
|
||||||
#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved."
|
#define FLAXENGINE_COPYRIGHT "Copyright (c) 2012-2021 Wojciech Figat. All rights reserved."
|
||||||
|
|
||||||
|
|||||||
@@ -228,6 +228,7 @@ static int64_t SetupHwTimer()
|
|||||||
uint32_t regs[4];
|
uint32_t regs[4];
|
||||||
CpuId( regs, 1 );
|
CpuId( regs, 1 );
|
||||||
if( !( regs[3] & ( 1 << 4 ) ) ) InitFailure( "CPU doesn't support RDTSC instruction." );
|
if( !( regs[3] & ( 1 << 4 ) ) ) InitFailure( "CPU doesn't support RDTSC instruction." );
|
||||||
|
#if !defined TRACY_NO_INVARIANT_CHECK
|
||||||
CpuId( regs, 0x80000007 );
|
CpuId( regs, 0x80000007 );
|
||||||
if( !( regs[3] & ( 1 << 8 ) ) )
|
if( !( regs[3] & ( 1 << 8 ) ) )
|
||||||
{
|
{
|
||||||
@@ -241,6 +242,7 @@ static int64_t SetupHwTimer()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return Profiler::GetTime();
|
return Profiler::GetTime();
|
||||||
|
|||||||
+17
@@ -12,8 +12,22 @@
|
|||||||
|
|
||||||
namespace tracy
|
namespace tracy
|
||||||
{
|
{
|
||||||
|
void ScopedZone::Begin(const SourceLocationData* srcloc)
|
||||||
|
{
|
||||||
|
#ifdef TRACY_ON_DEMAND
|
||||||
|
if (!GetProfiler().IsConnected()) return;
|
||||||
|
#endif
|
||||||
|
TracyLfqPrepare( QueueType::ZoneBegin );
|
||||||
|
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
|
||||||
|
MemWrite( &item->zoneBegin.srcloc, (uint64_t)srcloc );
|
||||||
|
TracyLfqCommit;
|
||||||
|
}
|
||||||
|
|
||||||
void ScopedZone::Begin(uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const Char* name, size_t nameSz)
|
void ScopedZone::Begin(uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const Char* name, size_t nameSz)
|
||||||
{
|
{
|
||||||
|
#ifdef TRACY_ON_DEMAND
|
||||||
|
if (!GetProfiler().IsConnected()) return;
|
||||||
|
#endif
|
||||||
TracyLfqPrepare( QueueType::ZoneBeginAllocSrcLoc );
|
TracyLfqPrepare( QueueType::ZoneBeginAllocSrcLoc );
|
||||||
const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );
|
const auto srcloc = Profiler::AllocSourceLocation( line, source, sourceSz, function, functionSz, name, nameSz );
|
||||||
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
|
MemWrite( &item->zoneBegin.time, Profiler::GetTime() );
|
||||||
@@ -23,6 +37,9 @@ void ScopedZone::Begin(uint32_t line, const char* source, size_t sourceSz, const
|
|||||||
|
|
||||||
void ScopedZone::End()
|
void ScopedZone::End()
|
||||||
{
|
{
|
||||||
|
#ifdef TRACY_ON_DEMAND
|
||||||
|
if (!GetProfiler().IsConnected()) return;
|
||||||
|
#endif
|
||||||
TracyLfqPrepare( QueueType::ZoneEnd );
|
TracyLfqPrepare( QueueType::ZoneEnd );
|
||||||
MemWrite( &item->zoneEnd.time, Profiler::GetTime() );
|
MemWrite( &item->zoneEnd.time, Profiler::GetTime() );
|
||||||
TracyLfqCommit;
|
TracyLfqCommit;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ struct TRACY_API SourceLocationData
|
|||||||
class TRACY_API ScopedZone
|
class TRACY_API ScopedZone
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
static void Begin( const SourceLocationData* srcloc );
|
||||||
static void Begin( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const Char* name, size_t nameSz );
|
static void Begin( uint32_t line, const char* source, size_t sourceSz, const char* function, size_t functionSz, const Char* name, size_t nameSz );
|
||||||
static void End();
|
static void End();
|
||||||
|
|
||||||
|
|||||||
+3
@@ -34,7 +34,10 @@ public class tracy : ThirdPartyModule
|
|||||||
|
|
||||||
options.PublicDefinitions.Add("TRACY_ENABLE");
|
options.PublicDefinitions.Add("TRACY_ENABLE");
|
||||||
if (options.Platform.Target == TargetPlatform.Windows)
|
if (options.Platform.Target == TargetPlatform.Windows)
|
||||||
|
{
|
||||||
options.PrivateDefinitions.Add("TRACY_DBGHELP_LOCK=DbgHelp");
|
options.PrivateDefinitions.Add("TRACY_DBGHELP_LOCK=DbgHelp");
|
||||||
|
options.PrivateDefinitions.Add("TRACY_NO_INVARIANT_CHECK");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -665,7 +665,11 @@ namespace Flax.Build.Bindings
|
|||||||
indent += " ";
|
indent += " ";
|
||||||
var eventInstance = eventInfo.IsStatic ? string.Empty : "__unmanagedPtr, ";
|
var eventInstance = eventInfo.IsStatic ? string.Empty : "__unmanagedPtr, ";
|
||||||
contents.Append(indent).Append($"add {{ Internal_{eventInfo.Name} += value; if (Internal_{eventInfo.Name}_Count++ == 0) Internal_{eventInfo.Name}_Bind({eventInstance}true); }}").AppendLine();
|
contents.Append(indent).Append($"add {{ Internal_{eventInfo.Name} += value; if (Internal_{eventInfo.Name}_Count++ == 0) Internal_{eventInfo.Name}_Bind({eventInstance}true); }}").AppendLine();
|
||||||
contents.Append(indent).Append($"remove {{ Internal_{eventInfo.Name} -= value; if (--Internal_{eventInfo.Name}_Count == 0) Internal_{eventInfo.Name}_Bind({eventInstance}false); }}").AppendLine();
|
contents.Append(indent).Append("remove { ").AppendLine();
|
||||||
|
contents.Append("#if FLAX_EDITOR || BUILD_DEBUG").AppendLine();
|
||||||
|
contents.Append(indent).Append($"if (Internal_{eventInfo.Name} != null) {{ bool invalid = true; foreach (Delegate e in Internal_{eventInfo.Name}.GetInvocationList()) {{ if (e == (Delegate)value) {{ invalid = false; break; }} }} if (invalid) throw new Exception(\"Cannot unregister from event if not registered before.\"); }}").AppendLine();
|
||||||
|
contents.Append("#endif").AppendLine();
|
||||||
|
contents.Append(indent).Append($"Internal_{eventInfo.Name} -= value; if (--Internal_{eventInfo.Name}_Count == 0) Internal_{eventInfo.Name}_Bind({eventInstance}false); }}").AppendLine();
|
||||||
indent = indent.Substring(0, indent.Length - 4);
|
indent = indent.Substring(0, indent.Length - 4);
|
||||||
contents.Append(indent).Append('}').AppendLine();
|
contents.Append(indent).Append('}').AppendLine();
|
||||||
|
|
||||||
|
|||||||
@@ -1028,7 +1028,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Script.ScriptVTable;");
|
contents.AppendLine(" auto scriptVTable = (MMethod**)managedTypePtr->Script.ScriptVTable;");
|
||||||
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableIndex}]);");
|
contents.AppendLine($" ASSERT(scriptVTable && scriptVTable[{scriptVTableIndex}]);");
|
||||||
contents.AppendLine($" auto method = scriptVTable[{scriptVTableIndex}];");
|
contents.AppendLine($" auto method = scriptVTable[{scriptVTableIndex}];");
|
||||||
contents.AppendLine(" PROFILE_CPU_NAMED(*method->ProfilerName);");
|
contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
|
||||||
contents.AppendLine(" MonoObject* exception = nullptr;");
|
contents.AppendLine(" MonoObject* exception = nullptr;");
|
||||||
|
|
||||||
contents.AppendLine(" auto prevWrapperCallInstance = WrapperCallInstance;");
|
contents.AppendLine(" auto prevWrapperCallInstance = WrapperCallInstance;");
|
||||||
@@ -1290,7 +1290,7 @@ namespace Flax.Build.Bindings
|
|||||||
contents.Append(" if (!mmethod)").AppendLine();
|
contents.Append(" if (!mmethod)").AppendLine();
|
||||||
contents.AppendFormat(" mmethod = {1}::TypeInitializer.GetType().ManagedClass->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
|
contents.AppendFormat(" mmethod = {1}::TypeInitializer.GetType().ManagedClass->GetMethod(\"Internal_{0}_Invoke\", {2});", eventInfo.Name, classTypeNameNative, paramsCount).AppendLine();
|
||||||
contents.Append(" CHECK(mmethod);").AppendLine();
|
contents.Append(" CHECK(mmethod);").AppendLine();
|
||||||
contents.Append(" PROFILE_CPU_NAMED(*mmethod->ProfilerName);").AppendLine();
|
contents.Append($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::On{eventInfo.Name}\");").AppendLine();
|
||||||
contents.Append(" MonoObject* exception = nullptr;").AppendLine();
|
contents.Append(" MonoObject* exception = nullptr;").AppendLine();
|
||||||
if (paramsCount == 0)
|
if (paramsCount == 0)
|
||||||
contents.AppendLine(" void** params = nullptr;");
|
contents.AppendLine(" void** params = nullptr;");
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user