Merge remote-tracking branch 'upstream/master' into FocusSelectedVJControls
This commit is contained in:
42
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/1-bug.yaml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Bug Report
|
||||
description: File a bug report.
|
||||
title: "[Bug]: "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this bug report! Please attach any minimal reproduction projects!
|
||||
- type: textarea
|
||||
id: description-area
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide a description of the bug and what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: steps-area
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Please provide reproduction steps if possible.
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: version
|
||||
attributes:
|
||||
label: Version
|
||||
description: What version of Flax are you running?
|
||||
options:
|
||||
- '1.8'
|
||||
- '1.9'
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
- master branch
|
||||
default: 3
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant logs
|
||||
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
||||
render: shell
|
||||
22
.github/ISSUE_TEMPLATE/2-feature-request.yaml
vendored
Normal file
22
.github/ISSUE_TEMPLATE/2-feature-request.yaml
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
name: Feature Request
|
||||
description: File a feature request.
|
||||
title: "[Request]: "
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out a feature request!
|
||||
- type: textarea
|
||||
id: description-area
|
||||
attributes:
|
||||
label: Description
|
||||
description: Please provide a description of the feature!
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: benefits-area
|
||||
attributes:
|
||||
label: Benefits
|
||||
description: Please provide what benefits this feature would provide to the engine!
|
||||
validations:
|
||||
required: true
|
||||
4
.github/workflows/build_ios.yml
vendored
4
.github/workflows/build_ios.yml
vendored
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v3
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
dotnet-version: 9.0.x
|
||||
- name: Setup .NET Workload
|
||||
run: |
|
||||
dotnet workload install ios
|
||||
@@ -33,4 +33,4 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Build
|
||||
run: |
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=8 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=9 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame
|
||||
|
||||
3
.github/workflows/build_linux.yml
vendored
3
.github/workflows/build_linux.yml
vendored
@@ -16,7 +16,8 @@ jobs:
|
||||
uses: actions/checkout@v3
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
|
||||
6
.github/workflows/cd.yml
vendored
6
.github/workflows/cd.yml
vendored
@@ -87,7 +87,8 @@ jobs:
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
@@ -118,7 +119,8 @@ jobs:
|
||||
git ${{ env.GIT_LFS_PULL_OPTIONS }} lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Setup Vulkan
|
||||
uses: ./.github/actions/vulkan
|
||||
- name: Setup .NET
|
||||
|
||||
3
.github/workflows/tests.yml
vendored
3
.github/workflows/tests.yml
vendored
@@ -28,7 +28,8 @@ jobs:
|
||||
git lfs pull
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --fix-missing libx11-dev libxcursor-dev libxinerama-dev build-essential gettext libtool libtool-bin libpulse-dev libasound2-dev libjack-dev portaudio19-dev
|
||||
- name: Build
|
||||
run: |
|
||||
./GenerateProjectFiles.sh -vs2022 -log -verbose -printSDKs -dotnet=8
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,6 +6,7 @@
|
||||
@3
|
||||
|
||||
#include "./Flax/Common.hlsl"
|
||||
#include "./Flax/Stencil.hlsl"
|
||||
#include "./Flax/MaterialCommon.hlsl"
|
||||
#include "./Flax/GBufferCommon.hlsl"
|
||||
@7
|
||||
@@ -14,10 +15,13 @@ META_CB_BEGIN(0, Data)
|
||||
float4x4 WorldMatrix;
|
||||
float4x4 InvWorld;
|
||||
float4x4 SvPositionToWorld;
|
||||
float3 Padding0;
|
||||
uint RenderLayersMask;
|
||||
@1META_CB_END
|
||||
|
||||
// Use depth buffer for per-pixel decal layering
|
||||
Texture2D DepthBuffer : register(t0);
|
||||
Texture2D<uint2> StencilBuffer : register(t1);
|
||||
|
||||
// Material shader resources
|
||||
@2
|
||||
@@ -200,6 +204,14 @@ void PS_Decal(
|
||||
#endif
|
||||
)
|
||||
{
|
||||
// Stencil masking
|
||||
uint stencilObjectLayer = STENCIL_BUFFER_OBJECT_LAYER(STENCIL_BUFFER_LOAD(StencilBuffer, SvPosition.xy));
|
||||
if ((RenderLayersMask & (1 << stencilObjectLayer)) == 0)
|
||||
{
|
||||
clip(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
float2 screenUV = SvPosition.xy * ScreenSize.zw;
|
||||
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;
|
||||
|
||||
|
||||
@@ -27,7 +27,15 @@ TextureCube EnvProbe : register(t__SRV__);
|
||||
TextureCube SkyLightTexture : register(t__SRV__);
|
||||
Buffer<float4> ShadowsBuffer : register(t__SRV__);
|
||||
Texture2D<float> ShadowMap : register(t__SRV__);
|
||||
Texture3D VolumetricFogTexture : register(t__SRV__);
|
||||
@4// Forward Shading: Utilities
|
||||
// Public accessors for lighting data, use them as data binding might change but those methods will remain.
|
||||
LightData GetDirectionalLight() { return DirectionalLight; }
|
||||
LightData GetSkyLight() { return SkyLight; }
|
||||
ProbeData GetEnvironmentProbe() { return EnvironmentProbe; }
|
||||
ExponentialHeightFogData GetExponentialHeightFog() { return ExponentialHeightFog; }
|
||||
uint GetLocalLightsCount() { return LocalLightsCount; }
|
||||
LightData GetLocalLight(uint i) { return LocalLights[i]; }
|
||||
@5// Forward Shading: Shaders
|
||||
|
||||
// Pixel Shader function for Forward Pass
|
||||
@@ -76,9 +84,8 @@ void PS_Forward(
|
||||
gBuffer.ShadingModel = MATERIAL_SHADING_MODEL;
|
||||
|
||||
// Calculate lighting from a single directional light
|
||||
float4 shadowMask = 1.0f;
|
||||
ShadowSample shadow = SampleDirectionalLightShadow(DirectionalLight, ShadowsBuffer, ShadowMap, gBuffer);
|
||||
shadowMask = GetShadowMask(shadow);
|
||||
float4 shadowMask = GetShadowMask(shadow);
|
||||
float4 light = GetLighting(ViewPos, DirectionalLight, gBuffer, shadowMask, false, false);
|
||||
|
||||
// Calculate lighting from sky light
|
||||
@@ -145,7 +152,25 @@ void PS_Forward(
|
||||
|
||||
#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
|
||||
// Calculate exponential height fog
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
|
||||
#if DIRECTX && FEATURE_LEVEL < FEATURE_LEVEL_SM6
|
||||
// TODO: fix D3D11/D3D10 bug with incorrect distance
|
||||
float fogSceneDistance = distance(materialInput.WorldPosition, ViewPos);
|
||||
#else
|
||||
float fogSceneDistance = gBuffer.ViewPos.z;
|
||||
#endif
|
||||
float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, fogSceneDistance);
|
||||
|
||||
if (ExponentialHeightFog.VolumetricFogMaxDistance > 0)
|
||||
{
|
||||
// Sample volumetric fog and mix it in
|
||||
float2 screenUV = materialInput.SvPosition.xy * ScreenSize.zw;
|
||||
float3 viewVector = materialInput.WorldPosition - ViewPos;
|
||||
float sceneDepth = length(viewVector);
|
||||
float depthSlice = sceneDepth / ExponentialHeightFog.VolumetricFogMaxDistance;
|
||||
float3 volumeUV = float3(screenUV, depthSlice);
|
||||
float4 volumetricFog = VolumetricFogTexture.SampleLevel(SamplerLinearClamp, volumeUV, 0);
|
||||
fog = CombineVolumetricFog(fog, volumetricFog);
|
||||
}
|
||||
|
||||
// Apply fog to the output color
|
||||
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE
|
||||
|
||||
@@ -21,7 +21,7 @@ float4 ViewInfo;
|
||||
float4 ScreenSize;
|
||||
float4 ViewSize;
|
||||
float3 ViewPadding0;
|
||||
float UnscaledTimeParam;
|
||||
float ScaledTimeParam;
|
||||
@1META_CB_END
|
||||
|
||||
// Shader resources
|
||||
|
||||
@@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
|
||||
materialInput.TBN = output.TBN;
|
||||
materialInput.TwoSidedSign = 1;
|
||||
materialInput.SvPosition = output.Position;
|
||||
materialInput.PreSkinnedPosition = Position;
|
||||
materialInput.PreSkinnedPosition = position;
|
||||
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
|
||||
materialInput.InstanceOrigin = output.InstanceOrigin;
|
||||
materialInput.InstanceParams = output.InstanceParams;
|
||||
|
||||
@@ -20,7 +20,7 @@ float4 ScreenSize;
|
||||
float4 TemporalAAJitter;
|
||||
float4x4 InverseViewProjectionMatrix;
|
||||
float3 ViewPadding0;
|
||||
float UnscaledTimeParam;
|
||||
float ScaledTimeParam;
|
||||
@1META_CB_END
|
||||
|
||||
// Shader resources
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/BitonicSort.flax
LFS
BIN
Content/Shaders/BitonicSort.flax
LFS
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/Fog.flax
LFS
BIN
Content/Shaders/Fog.flax
LFS
Binary file not shown.
BIN
Content/Shaders/GI/DDGI.flax
LFS
BIN
Content/Shaders/GI/DDGI.flax
LFS
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/MotionBlur.flax
LFS
BIN
Content/Shaders/MotionBlur.flax
LFS
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Content/Shaders/Reflections.flax
LFS
BIN
Content/Shaders/Reflections.flax
LFS
Binary file not shown.
BIN
Content/Shaders/SDF.flax
LFS
BIN
Content/Shaders/SDF.flax
LFS
Binary file not shown.
BIN
Content/Shaders/SSR.flax
LFS
BIN
Content/Shaders/SSR.flax
LFS
Binary file not shown.
BIN
Content/Shaders/Sky.flax
LFS
BIN
Content/Shaders/Sky.flax
LFS
Binary file not shown.
Binary file not shown.
@@ -2,9 +2,9 @@
|
||||
"Name": "Flax",
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 10,
|
||||
"Minor": 11,
|
||||
"Revision": 0,
|
||||
"Build": 6705
|
||||
"Build": 6806
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<!-- Please search existing issues for potential duplicates before filing yours:
|
||||
https://github.com/flaxengine/FlaxEngine/issues?q=is%3Aissue
|
||||
-->
|
||||
|
||||
**Issue description:**
|
||||
<!-- What happened, and what was expected. -->
|
||||
<!-- Log file, can be found in the project directory's `Logs` folder (optional) -->
|
||||
|
||||
**Steps to reproduce:**
|
||||
<!-- Enter minimal reproduction steps if available. -->
|
||||
|
||||
|
||||
**Minimal reproduction project:**
|
||||
<!-- Recommended as it greatly speeds up debugging. Drag and drop a zip archive to upload it. -->
|
||||
|
||||
|
||||
**Flax version:**
|
||||
<!-- Specify version number. -->
|
||||
|
||||
@@ -49,7 +49,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Fedora: `sudo dnf install dotnet-sdk-8.0`
|
||||
* Arch: `sudo pacman -S dotnet-sdk-8.0 dotnet-runtime-8.0 dotnet-targeting-pack-8.0 dotnet-host`
|
||||
* Install Vulkan SDK ([https://vulkan.lunarg.com/](https://vulkan.lunarg.com/))
|
||||
* Ubuntu: `sudo apt install vulkan-sdk`
|
||||
* Ubuntu: `sudo apt install vulkan-sdk` (deprecated, follow official docs)
|
||||
* Fedora: `sudo dnf install vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Arch: `sudo pacman -S vulkan-headers vulkan-tools vulkan-validation-layers`
|
||||
* Install Git with LFS
|
||||
@@ -60,7 +60,7 @@ Follow the instructions below to compile and run the engine from source.
|
||||
* Ubuntu: `sudo apt-get install libx11-dev libxcursor-dev libxinerama-dev zlib1g-dev`
|
||||
* Fedora: `sudo dnf install libX11-devel libXcursor-devel libXinerama-devel ghc-zlib-devel`
|
||||
* Arch: `sudo pacman -S base-devel libx11 libxcursor libxinerama zlib`
|
||||
* Install Clang compiler (version 6 or later):
|
||||
* Install Clang compiler (version 14 or later):
|
||||
* Ubuntu: `sudo apt-get install clang lldb lld`
|
||||
* Fedora: `sudo dnf install clang llvm lldb lld`
|
||||
* Arch: `sudo pacman -S clang lldb lld`
|
||||
|
||||
@@ -174,7 +174,9 @@ void EditorAnalytics::StartSession()
|
||||
// Bind events
|
||||
GameCooker::OnEvent.Bind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Bind<RegisterLightmapsBuildingStart>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnError.Bind<RegisterError>();
|
||||
#endif
|
||||
}
|
||||
|
||||
void EditorAnalytics::EndSession()
|
||||
@@ -187,7 +189,9 @@ void EditorAnalytics::EndSession()
|
||||
// Unbind events
|
||||
GameCooker::OnEvent.Unbind<RegisterGameCookingStart>();
|
||||
ShadowsOfMordor::Builder::Instance()->OnBuildStarted.Unbind<RegisterLightmapsBuildingStart>();
|
||||
#if LOG_ENABLE
|
||||
Log::Logger::OnError.Unbind<RegisterError>();
|
||||
#endif
|
||||
|
||||
// End session
|
||||
{
|
||||
|
||||
@@ -117,7 +117,8 @@ namespace FlaxEditor.Content.Create
|
||||
|
||||
private static bool IsValid(Type type)
|
||||
{
|
||||
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
|
||||
var controlTypes = Editor.Instance.CodeEditing.Controls.Get();
|
||||
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -281,6 +281,13 @@ namespace FlaxEditor.Content
|
||||
|
||||
private void CacheData()
|
||||
{
|
||||
if (!_asset)
|
||||
{
|
||||
_parameters = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
_methods = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||
_attributes = Utils.GetEmptyArray<Attribute>();
|
||||
return;
|
||||
}
|
||||
if (_parameters != null)
|
||||
return;
|
||||
if (_asset.WaitForLoaded())
|
||||
@@ -344,13 +351,13 @@ namespace FlaxEditor.Content
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Name => Path.GetFileNameWithoutExtension(_asset.Path);
|
||||
public string Name => _asset ? Path.GetFileNameWithoutExtension(_asset.Path) : null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string Namespace => string.Empty;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string TypeName => JsonSerializer.GetStringID(_asset.ID);
|
||||
public string TypeName => _asset ? JsonSerializer.GetStringID(_asset.ID) : null;
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsPublic => true;
|
||||
|
||||
@@ -130,6 +130,11 @@ namespace FlaxEditor.Content
|
||||
eyeAdaptation.Mode = EyeAdaptationMode.None;
|
||||
eyeAdaptation.OverrideFlags |= EyeAdaptationSettingsOverride.Mode;
|
||||
preview.PostFxVolume.EyeAdaptation = eyeAdaptation;
|
||||
|
||||
var antiAliasing = preview.PostFxVolume.AntiAliasing;
|
||||
antiAliasing.Mode = AntialiasingMode.FastApproximateAntialiasing;
|
||||
antiAliasing.OverrideFlags |= AntiAliasingSettingsOverride.Mode;
|
||||
preview.PostFxVolume.AntiAliasing = antiAliasing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,13 +20,6 @@ class PlatformTools;
|
||||
#define GAME_BUILD_DOTNET_RUNTIME_MAX_VER 9
|
||||
#endif
|
||||
|
||||
#if OFFICIAL_BUILD
|
||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("-dotnet=" MACRO_TO_STR(GAME_BUILD_DOTNET_RUNTIME_MIN_VER))
|
||||
#else
|
||||
#define GAME_BUILD_DOTNET_VER TEXT("")
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Game building options. Used as flags.
|
||||
/// </summary>
|
||||
@@ -374,6 +367,8 @@ public:
|
||||
/// </summary>
|
||||
void GetBuildPlatformName(const Char*& platform, const Char*& architecture) const;
|
||||
|
||||
String GetDotnetCommandArg() const;
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Content/JsonAsset.h"
|
||||
#include "Engine/Content/AssetReference.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
#include "Platform/Windows/WindowsPlatformTools.h"
|
||||
#include "Engine/Platform/Windows/WindowsPlatformSettings.h"
|
||||
@@ -311,6 +312,14 @@ void CookingData::GetBuildPlatformName(const Char*& platform, const Char*& archi
|
||||
}
|
||||
}
|
||||
|
||||
String CookingData::GetDotnetCommandArg() const
|
||||
{
|
||||
int32 version = Tools->GetDotnetVersion();
|
||||
if (version == 0)
|
||||
return String::Empty;
|
||||
return String::Format(TEXT("-dotnet={}"), version);
|
||||
}
|
||||
|
||||
void CookingData::StepProgress(const String& info, const float stepProgress) const
|
||||
{
|
||||
const float singleStepProgress = 1.0f / (StepsCount + 1);
|
||||
@@ -380,6 +389,7 @@ bool GameCooker::IsCancelRequested()
|
||||
|
||||
PlatformTools* GameCooker::GetTools(BuildPlatform platform)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
PlatformTools* result = nullptr;
|
||||
if (!Tools.TryGet(platform, result))
|
||||
{
|
||||
@@ -471,6 +481,7 @@ bool GameCooker::Build(BuildPlatform platform, BuildConfiguration configuration,
|
||||
LOG(Error, "Build platform {0} is not supported.", ::ToString(platform));
|
||||
return true;
|
||||
}
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Setup
|
||||
CancelFlag = 0;
|
||||
@@ -624,6 +635,7 @@ void GameCookerImpl::ReportProgress(const String& info, float totalProgress)
|
||||
|
||||
void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
if (Internal_OnCollectAssets == nullptr)
|
||||
{
|
||||
auto c = GameCooker::GetStaticClass();
|
||||
@@ -651,6 +663,7 @@ void GameCookerImpl::OnCollectAssets(HashSet<Guid>& assets)
|
||||
|
||||
bool GameCookerImpl::Build()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
CookingData& data = *Data;
|
||||
LOG(Info, "Starting Game Cooker...");
|
||||
LOG(Info, "Platform: {0}, Configuration: {2}, Options: {1}", ::ToString(data.Platform), (int32)data.Options, ::ToString(data.Configuration));
|
||||
@@ -670,8 +683,7 @@ bool GameCookerImpl::Build()
|
||||
|
||||
MCore::Thread::Attach();
|
||||
|
||||
// Build Started
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
// Build start
|
||||
{
|
||||
CallEvent(GameCooker::EventType::BuildStarted);
|
||||
data.Tools->OnBuildStarted(data);
|
||||
@@ -744,8 +756,8 @@ bool GameCookerImpl::Build()
|
||||
}
|
||||
IsRunning = false;
|
||||
CancelFlag = 0;
|
||||
if (!EnumHasAnyFlags(data.Options, BuildOptions::NoCook))
|
||||
{
|
||||
// Build end
|
||||
for (int32 stepIndex = 0; stepIndex < Steps.Count(); stepIndex++)
|
||||
Steps[stepIndex]->OnBuildEnded(data, failed);
|
||||
data.Tools->OnBuildEnded(data, failed);
|
||||
@@ -778,6 +790,8 @@ int32 GameCookerImpl::ThreadFunction()
|
||||
|
||||
bool GameCookerService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
auto editorAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
editorAssembly->Unloading.Bind(OnEditorAssemblyUnloading);
|
||||
GameCooker::OnCollectAssets.Bind(OnCollectAssets);
|
||||
@@ -789,6 +803,7 @@ void GameCookerService::Update()
|
||||
{
|
||||
if (IsRunning)
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
ScopeLock lock(ProgressLocker);
|
||||
|
||||
if (ProgressMsg.HasChars())
|
||||
|
||||
@@ -15,26 +15,32 @@
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
|
||||
GDKPlatformTools::GDKPlatformTools()
|
||||
String GetGDK()
|
||||
{
|
||||
// Find GDK
|
||||
Platform::GetEnvironmentVariable(TEXT("GameDKLatest"), _gdkPath);
|
||||
if (_gdkPath.IsEmpty() || !FileSystem::DirectoryExists(_gdkPath))
|
||||
String gdk;
|
||||
Platform::GetEnvironmentVariable(TEXT("GameDKLatest"), gdk);
|
||||
if (gdk.IsEmpty() || !FileSystem::DirectoryExists(gdk))
|
||||
{
|
||||
_gdkPath.Clear();
|
||||
Platform::GetEnvironmentVariable(TEXT("GRDKLatest"), _gdkPath);
|
||||
if (_gdkPath.IsEmpty() || !FileSystem::DirectoryExists(_gdkPath))
|
||||
gdk.Clear();
|
||||
Platform::GetEnvironmentVariable(TEXT("GRDKLatest"), gdk);
|
||||
if (gdk.IsEmpty() || !FileSystem::DirectoryExists(gdk))
|
||||
{
|
||||
_gdkPath.Clear();
|
||||
gdk.Clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_gdkPath.EndsWith(TEXT("GRDK\\")))
|
||||
_gdkPath.Remove(_gdkPath.Length() - 6);
|
||||
else if (_gdkPath.EndsWith(TEXT("GRDK")))
|
||||
_gdkPath.Remove(_gdkPath.Length() - 5);
|
||||
if (gdk.EndsWith(TEXT("GRDK\\")))
|
||||
gdk.Remove(gdk.Length() - 6);
|
||||
else if (gdk.EndsWith(TEXT("GRDK")))
|
||||
gdk.Remove(gdk.Length() - 5);
|
||||
}
|
||||
}
|
||||
return gdk;
|
||||
}
|
||||
|
||||
GDKPlatformTools::GDKPlatformTools()
|
||||
{
|
||||
_gdkPath = GetGDK();
|
||||
}
|
||||
|
||||
DotNetAOTModes GDKPlatformTools::UseAOT() const
|
||||
@@ -121,7 +127,7 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
validName.Add('\0');
|
||||
|
||||
sb.Append(TEXT("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
|
||||
sb.Append(TEXT("<Game configVersion=\"0\">\n"));
|
||||
sb.Append(TEXT("<Game configVersion=\"1\">\n"));
|
||||
sb.AppendFormat(TEXT(" <Identity Name=\"{0}\" Publisher=\"{1}\" Version=\"{2}\"/>\n"),
|
||||
validName.Get(),
|
||||
platformSettings->PublisherName.HasChars() ? platformSettings->PublisherName : TEXT("CN=") + gameSettings->CompanyName,
|
||||
@@ -195,4 +201,9 @@ bool GDKPlatformTools::OnPostProcess(CookingData& data, GDKPlatformSettings* pla
|
||||
return false;
|
||||
}
|
||||
|
||||
int32 GDKPlatformTools::GetDotnetVersion() const
|
||||
{
|
||||
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ public:
|
||||
public:
|
||||
|
||||
// [PlatformTools]
|
||||
int32 GetDotnetVersion() const override;
|
||||
DotNetAOTModes UseAOT() const override;
|
||||
bool OnDeployBinaries(CookingData& data) override;
|
||||
};
|
||||
|
||||
@@ -186,7 +186,7 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
ADD_ENTRY("CFBundlePackageType", "APPL");
|
||||
ADD_ENTRY("NSPrincipalClass", "NSApplication");
|
||||
ADD_ENTRY("LSApplicationCategoryType", "public.app-category.games");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "10.15");
|
||||
ADD_ENTRY("LSMinimumSystemVersion", "13");
|
||||
ADD_ENTRY("CFBundleIconFile", "icon.icns");
|
||||
ADD_ENTRY_STR("CFBundleExecutable", executableName);
|
||||
ADD_ENTRY_STR("CFBundleIdentifier", appIdentifier);
|
||||
@@ -231,6 +231,8 @@ bool MacPlatformTools::OnPostProcess(CookingData& data)
|
||||
LOG(Info, "Building app package...");
|
||||
{
|
||||
const String dmgPath = data.OriginalOutputPath / appName + TEXT(".dmg");
|
||||
if (FileSystem::FileExists(dmgPath))
|
||||
FileSystem::DeleteFile(dmgPath);
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.HiddenWindow = true;
|
||||
procSettings.WorkingDirectory = data.OriginalOutputPath;
|
||||
|
||||
@@ -528,6 +528,9 @@ bool WindowsPlatformTools::OnDeployBinaries(CookingData& data)
|
||||
|
||||
void WindowsPlatformTools::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
if (EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||
return;
|
||||
|
||||
// Remove old executable
|
||||
Array<String> files;
|
||||
FileSystem::DirectoryGetFiles(files, data.NativeCodeOutputPath, TEXT("*.exe"), DirectorySearchOption::TopDirectoryOnly);
|
||||
|
||||
@@ -70,6 +70,20 @@ public:
|
||||
/// </summary>
|
||||
virtual ArchitectureType GetArchitecture() const = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the .Net version to use for the cooked game.
|
||||
/// </summary>
|
||||
virtual int32 GetDotnetVersion() const
|
||||
{
|
||||
#if OFFICIAL_BUILD
|
||||
// Use the fixed .NET SDK version in packaged builds for compatibility (FlaxGame is precompiled with it)
|
||||
return GAME_BUILD_DOTNET_RUNTIME_MIN_VER;
|
||||
#else
|
||||
// Use the highest version found on a system (Flax.Build will decide)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value indicating whenever platform requires AOT (needs C# assemblies to be precompiled).
|
||||
/// </summary>
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
#include "Engine/Serialization/JsonTools.h"
|
||||
#include "Engine/Serialization/JsonWriters.h"
|
||||
#include "Editor/Cooker/PlatformTools.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Editor.h"
|
||||
#include "Editor/ProjectInfo.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Editor/Utilities/EditorUtilities.h"
|
||||
#if PLATFORM_MAC
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
@@ -127,7 +128,7 @@ bool CompileScriptsStep::DeployBinaries(CookingData& data, const String& path, c
|
||||
const String dst = dstPath / StringUtils::GetFileName(file);
|
||||
if (dst == file)
|
||||
continue;
|
||||
if (FileSystem::CopyFile(dst, file))
|
||||
if (EditorUtilities::CopyFileIfNewer(dst, file))
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to copy file from {0} to {1}."), file, dst));
|
||||
return true;
|
||||
@@ -189,7 +190,7 @@ bool CompileScriptsStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("CompileLog.txt");
|
||||
auto args = String::Format(
|
||||
TEXT("-log -logfile=\"{4}\" -build -mutex -buildtargets={0} -platform={1} -arch={2} -configuration={3} -aotMode={5} {6}"),
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), GAME_BUILD_DOTNET_VER);
|
||||
target, platform, architecture, configuration, logFile, ToString(data.Tools->UseAOT()), data.GetDotnetCommandArg());
|
||||
#if PLATFORM_WINDOWS
|
||||
if (data.Platform == BuildPlatform::LinuxX64)
|
||||
#elif PLATFORM_LINUX
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "Engine/Engine/Base/GameBase.h"
|
||||
#include "Engine/Engine/Globals.h"
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
#if PLATFORM_TOOLS_WINDOWS
|
||||
@@ -525,6 +526,7 @@ bool ProcessShaderBase(CookAssetsStep::AssetCookData& data, ShaderAssetBase* ass
|
||||
#if PLATFORM_TOOLS_XBOX_SCARLETT
|
||||
case BuildPlatform::XboxScarlett:
|
||||
{
|
||||
options.Platform = PlatformType::XboxScarlett;
|
||||
const char* platformDefineName = "PLATFORM_XBOX_SCARLETT";
|
||||
COMPILE_PROFILE(DirectX_SM6, SHADER_FILE_CHUNK_INTERNAL_D3D_SM6_CACHE);
|
||||
break;
|
||||
@@ -1366,7 +1368,10 @@ bool CookAssetsStep::Perform(CookingData& data)
|
||||
{
|
||||
typeName = e.TypeName;
|
||||
}
|
||||
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
||||
if (e.Count == 1)
|
||||
LOG(Info, "{0}: 1 asset of total size {1}", typeName, Utilities::BytesToText(e.ContentSize));
|
||||
else
|
||||
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
||||
}
|
||||
LOG(Info, "");
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
{
|
||||
// Ask Flax.Build to provide .NET SDK location for the current platform
|
||||
String sdks;
|
||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), GAME_BUILD_DOTNET_VER), data.CacheDirectory);
|
||||
bool failed = ScriptsBuilder::RunBuildTool(String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printSDKs {}"), data.GetDotnetCommandArg()), data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
int32 idx = sdks.Find(TEXT("DotNetSdk, "), StringSearchCase::CaseSensitive);
|
||||
if (idx != -1)
|
||||
@@ -200,7 +200,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
String sdks;
|
||||
const Char *platformName, *archName;
|
||||
data.GetBuildPlatformName(platformName, archName);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, GAME_BUILD_DOTNET_VER);
|
||||
String args = String::Format(TEXT("-log -logMessagesOnly -logFileWithConsole -logfile=SDKs.txt -printDotNetRuntime -platform={} -arch={} {}"), platformName, archName, data.GetDotnetCommandArg());
|
||||
bool failed = ScriptsBuilder::RunBuildTool(args, data.CacheDirectory);
|
||||
failed |= File::ReadAllText(data.CacheDirectory / TEXT("SDKs.txt"), sdks);
|
||||
Array<String> parts;
|
||||
@@ -244,10 +244,13 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
int32 minVer = GAME_BUILD_DOTNET_RUNTIME_MIN_VER, maxVer = GAME_BUILD_DOTNET_RUNTIME_MAX_VER;
|
||||
if (srcDotnetFromEngine)
|
||||
{
|
||||
// Detect version from runtime files inside Engine Platform folder
|
||||
for (int32 i = GAME_BUILD_DOTNET_RUNTIME_MAX_VER; i >= GAME_BUILD_DOTNET_RUNTIME_MIN_VER; i--)
|
||||
if (data.Tools->GetDotnetVersion() != 0)
|
||||
minVer = maxVer = data.Tools->GetDotnetVersion();
|
||||
for (int32 i = maxVer; i >= minVer; i--)
|
||||
{
|
||||
// Check runtime files inside Engine Platform folder
|
||||
String testPath1 = srcDotnet / String::Format(TEXT("lib/net{}.0"), i);
|
||||
@@ -262,7 +265,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
}
|
||||
if (version.IsEmpty())
|
||||
{
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version for the current host platform."), GAME_BUILD_DOTNET_RUNTIME_MIN_VER));
|
||||
data.Error(String::Format(TEXT("Failed to find supported .NET {} version (min {}) for {} platform."), maxVer, minVer, platformName));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -364,7 +367,7 @@ bool DeployDataStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("StripDotnetLibs.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetClassLibStripping -mutex -binaries=\"{}\" {}"),
|
||||
logFile, data.DataOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
logFile, data.DataOutputPath, data.GetDotnetCommandArg());
|
||||
for (const String& define : data.CustomDefines)
|
||||
{
|
||||
args += TEXT(" -D");
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
void PrecompileAssembliesStep::OnBuildStarted(CookingData& data)
|
||||
{
|
||||
const DotNetAOTModes aotMode = data.Tools->UseAOT();
|
||||
if (aotMode == DotNetAOTModes::None)
|
||||
if (aotMode == DotNetAOTModes::None || EnumHasAllFlags(data.Options, BuildOptions::NoCook))
|
||||
return;
|
||||
const auto& buildSettings = *BuildSettings::Get();
|
||||
|
||||
@@ -59,6 +59,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
data.StepProgress(infoMsg, 0);
|
||||
|
||||
// Override Newtonsoft.Json with AOT-version (one that doesn't use System.Reflection.Emit)
|
||||
// TODO: remove it since EngineModule does properly reference AOT lib now
|
||||
EditorUtilities::CopyFileIfNewer(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.dll"), Globals::StartupFolder / TEXT("Source/Platforms/DotNet/AOT/Newtonsoft.Json.dll"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.xml"));
|
||||
FileSystem::DeleteFile(data.ManagedCodeOutputPath / TEXT("Newtonsoft.Json.pdb"));
|
||||
@@ -69,7 +70,7 @@ bool PrecompileAssembliesStep::Perform(CookingData& data)
|
||||
const String logFile = data.CacheDirectory / TEXT("AOTLog.txt");
|
||||
String args = String::Format(
|
||||
TEXT("-log -logfile=\"{}\" -runDotNetAOT -mutex -platform={} -arch={} -configuration={} -aotMode={} -binaries=\"{}\" -intermediate=\"{}\" {}"),
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, GAME_BUILD_DOTNET_VER);
|
||||
logFile, platform, architecture, configuration, ToString(aotMode), data.DataOutputPath, data.ManagedCodeOutputPath, data.GetDotnetCommandArg());
|
||||
if (!buildSettings.SkipUnusedDotnetLibsPackaging)
|
||||
args += TEXT(" -skipUnusedDotnetLibs=false"); // Run AOT on whole class library (not just used libs)
|
||||
for (const String& define : data.CustomDefines)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Types/Stopwatch.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
@@ -69,6 +71,7 @@ MTypeObject* CustomEditorsUtil::GetCustomEditor(MTypeObject* refType)
|
||||
|
||||
bool CustomEditorsUtilService::Init()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
TRACK_ASSEMBLY(((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly);
|
||||
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
|
||||
|
||||
@@ -77,6 +80,8 @@ bool CustomEditorsUtilService::Init()
|
||||
|
||||
void OnAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
PROFILE_CPU_NAMED("CustomEditors.OnAssemblyLoaded");
|
||||
PROFILE_MEM(Editor);
|
||||
Stopwatch stopwatch;
|
||||
|
||||
// Prepare FlaxEngine
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
public class AudioSourceEditor : ActorEditor
|
||||
{
|
||||
private Label _infoLabel;
|
||||
private Slider _slider;
|
||||
private AudioSource.States _slideStartState;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -28,6 +30,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_infoLabel = playbackGroup.Label(string.Empty).Label;
|
||||
_infoLabel.AutoHeight = true;
|
||||
|
||||
// Play back slider
|
||||
var sliderElement = playbackGroup.CustomContainer<Slider>();
|
||||
_slider = sliderElement.CustomControl;
|
||||
_slider.ThumbSize = new Float2(_slider.ThumbSize.X * 0.5f, _slider.ThumbSize.Y);
|
||||
_slider.SlidingStart += OnSlidingStart;
|
||||
_slider.SlidingEnd += OnSlidingEnd;
|
||||
|
||||
var grid = playbackGroup.UniformGrid();
|
||||
var gridControl = grid.CustomControl;
|
||||
gridControl.ClipChildren = false;
|
||||
@@ -40,6 +49,38 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSlidingEnd()
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is AudioSource audioSource && audioSource.Clip)
|
||||
{
|
||||
switch (_slideStartState)
|
||||
{
|
||||
case AudioSource.States.Playing:
|
||||
audioSource.Play();
|
||||
break;
|
||||
case AudioSource.States.Paused:
|
||||
case AudioSource.States.Stopped:
|
||||
audioSource.Pause();
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSlidingStart()
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is AudioSource audioSource && audioSource.Clip)
|
||||
{
|
||||
_slideStartState = audioSource.State;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Refresh()
|
||||
{
|
||||
@@ -51,7 +92,29 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is AudioSource audioSource && audioSource.Clip)
|
||||
{
|
||||
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n";
|
||||
_slider.Maximum = audioSource.Clip.Length;
|
||||
_slider.Minimum = 0;
|
||||
if (_slider.IsSliding)
|
||||
{
|
||||
if (audioSource.State != AudioSource.States.Playing)
|
||||
{
|
||||
// Play to move slider correctly
|
||||
audioSource.Play();
|
||||
audioSource.Time = _slider.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
audioSource.Time = _slider.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_slider.Value = audioSource.Time;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
_infoLabel.Text = text;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
[CustomEditor(typeof(EnvironmentProbe)), DefaultEditor]
|
||||
public class EnvironmentProbeEditor : ActorEditor
|
||||
{
|
||||
private FlaxEngine.GUI.Button _bake;
|
||||
private Button _bake;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -20,8 +21,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
if (Values.HasDifferentTypes == false)
|
||||
{
|
||||
layout.Space(10);
|
||||
_bake = layout.Button("Bake").Button;
|
||||
var group = layout.Group("Bake");
|
||||
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||
_bake = group.Button("Bake").Button;
|
||||
_bake.Clicked += BakeButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
private void OnImageClicked(Image image, MouseButton button)
|
||||
{
|
||||
var texture = Values[0] as GPUTexture;
|
||||
if (!texture)
|
||||
if (!texture || button != MouseButton.Right)
|
||||
return;
|
||||
var menu = new ContextMenu();
|
||||
menu.AddButton("Save...", () => Screenshot.Capture(Values[0] as GPUTexture));
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom editor for <see cref="NavMeshBoundsVolume"/>.
|
||||
/// </summary>
|
||||
/// <seealso cref="ActorEditor" />
|
||||
[CustomEditor(typeof(NavMeshBoundsVolume)), DefaultEditor]
|
||||
internal class NavMeshBoundsVolumeEditor : ActorEditor
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
if (Values.HasDifferentTypes == false)
|
||||
{
|
||||
var button = layout.Button("Build");
|
||||
button.Button.Clicked += OnBuildClicked;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBuildClicked()
|
||||
{
|
||||
foreach (var value in Values)
|
||||
{
|
||||
if (value is NavMeshBoundsVolume volume)
|
||||
{
|
||||
Navigation.BuildNavMesh(volume.Box, volume.Scene);
|
||||
Editor.Instance.Scene.MarkSceneEdited(volume.Scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection.Emit;
|
||||
using FlaxEditor.CustomEditors.GUI;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
ScriptName = scriptName;
|
||||
TooltipText = "Create a new script";
|
||||
DrawHighlights = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
|
||||
_addScriptsButton = new Button
|
||||
{
|
||||
TooltipText = "Add new scripts to the actor",
|
||||
TooltipText = "Add new scripts to the actor.",
|
||||
AnchorPreset = AnchorPresets.MiddleCenter,
|
||||
Text = buttonText,
|
||||
Parent = this,
|
||||
@@ -114,7 +115,16 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
cm.TextChanged += text =>
|
||||
{
|
||||
if (!IsValidScriptName(text))
|
||||
{
|
||||
// Remove NewScriptItems
|
||||
List<Control> newScriptItems = cm.ItemsPanel.Children.FindAll(c => c is NewScriptItem);
|
||||
foreach (var item in newScriptItems)
|
||||
{
|
||||
cm.ItemsPanel.RemoveChild(item);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem))
|
||||
{
|
||||
// If there are no visible items, that means the search failed so we can find the create script button or create one if it's the first time
|
||||
@@ -876,7 +886,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Add drag button to the group
|
||||
var scriptDrag = new DragImage
|
||||
{
|
||||
TooltipText = "Script reference",
|
||||
TooltipText = "Script reference.",
|
||||
AutoFocus = true,
|
||||
IsScrollable = false,
|
||||
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,
|
||||
@@ -899,14 +909,17 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
settingsButton.Tag = script;
|
||||
settingsButton.Clicked += OnSettingsButtonClicked;
|
||||
|
||||
group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
|
||||
// Adjust margin to not overlap with other ui elements in the header
|
||||
group.Panel.HeaderTextMargin = group.Panel.HeaderTextMargin with { Left = scriptDrag.Right - 12, Right = settingsButton.Width + Utilities.Constants.UIMargin };
|
||||
group.Object(values, editor);
|
||||
// Remove drop down arrows and containment lines if no objects in the group
|
||||
if (group.Children.Count == 0)
|
||||
{
|
||||
group.Panel.Close();
|
||||
group.Panel.ArrowImageOpened = null;
|
||||
group.Panel.ArrowImageClosed = null;
|
||||
group.Panel.EnableContainmentLines = false;
|
||||
group.Panel.CanOpenClose = false;
|
||||
}
|
||||
|
||||
// Scripts arrange bar
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
@@ -19,8 +20,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
if (Values.HasDifferentTypes == false)
|
||||
{
|
||||
// Add 'Bake' button
|
||||
layout.Space(10);
|
||||
var button = layout.Button("Bake");
|
||||
var group = layout.Group("Bake");
|
||||
group.Panel.ItemsMargin = new Margin(Utilities.Constants.UIMargin * 2);
|
||||
var button = group.Button("Bake");
|
||||
button.Button.Clicked += BakeButtonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +123,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
base.Refresh();
|
||||
|
||||
if (Picker == null)
|
||||
return;
|
||||
var differentValues = HasDifferentValues;
|
||||
Picker.DifferentValues = differentValues;
|
||||
if (!differentValues)
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
menu.AddButton("Copy", linkedEditor.Copy);
|
||||
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
b.Enabled = !Editor._readOnly && Editor._canResize;
|
||||
b = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
|
||||
@@ -407,7 +407,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
menu.AddButton("Copy", linkedEditor.Copy);
|
||||
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
b.Enabled = !Editor._readOnly && Editor._canResize;
|
||||
var paste = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
|
||||
@@ -422,7 +422,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
moveDownButton.Enabled = Index + 1 < Editor.Count;
|
||||
}
|
||||
|
||||
menu.AddButton("Remove", OnRemoveClicked);
|
||||
b = menu.AddButton("Remove", OnRemoveClicked);
|
||||
b.Enabled = !Editor._readOnly && Editor._canResize;
|
||||
|
||||
menu.Show(panel, location);
|
||||
}
|
||||
@@ -449,6 +450,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
protected bool NotNullItems;
|
||||
|
||||
private IntValueBox _sizeBox;
|
||||
private Label _label;
|
||||
private Color _background;
|
||||
private int _elementsCount, _minCount, _maxCount;
|
||||
private bool _readOnly;
|
||||
@@ -565,7 +567,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Parent = dropPanel,
|
||||
};
|
||||
|
||||
var label = new Label
|
||||
_label = new Label
|
||||
{
|
||||
Text = "Size",
|
||||
AnchorPreset = AnchorPresets.TopRight,
|
||||
@@ -591,11 +593,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
panel.Panel.Offsets = new Margin(7, 7, 0, 0);
|
||||
panel.Panel.BackgroundColor = _background;
|
||||
var elementType = ElementType;
|
||||
var bindingAttr = System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public;
|
||||
bool single = elementType.IsPrimitive ||
|
||||
elementType.Equals(new ScriptType(typeof(string))) ||
|
||||
elementType.IsEnum ||
|
||||
(elementType.GetFields().Length == 1 && elementType.GetProperties().Length == 0) ||
|
||||
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
|
||||
(elementType.GetFields(bindingAttr).Length == 1 && elementType.GetProperties(bindingAttr).Length == 0) ||
|
||||
(elementType.GetProperties(bindingAttr).Length == 1 && elementType.GetFields(bindingAttr).Length == 0) ||
|
||||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
||||
elementType.Equals(new ScriptType(typeof(SettingsBase)));
|
||||
if (_cachedDropPanels == null)
|
||||
@@ -649,7 +652,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
panel.Panel.Size = new Float2(0, 18);
|
||||
panel.Panel.Margin = new Margin(0, 0, Utilities.Constants.UIMargin, 0);
|
||||
|
||||
var removeButton = panel.Button("-", "Remove the last item");
|
||||
var removeButton = panel.Button("-", "Remove the last item.");
|
||||
removeButton.Button.Size = new Float2(16, 16);
|
||||
removeButton.Button.Enabled = size > _minCount;
|
||||
removeButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
@@ -660,7 +663,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Resize(Count - 1);
|
||||
};
|
||||
|
||||
var addButton = panel.Button("+", "Add a new item");
|
||||
var addButton = panel.Button("+", "Add a new item.");
|
||||
addButton.Button.Size = new Float2(16, 16);
|
||||
addButton.Button.Enabled = (!NotNullItems || size > 0) && size < _maxCount;
|
||||
addButton.Button.AnchorPreset = AnchorPresets.TopRight;
|
||||
@@ -671,8 +674,10 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Resize(Count + 1);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Layout.ContainerControl.SizeChanged += OnLayoutSizeChanged;
|
||||
}
|
||||
|
||||
private void OnSetupContextMenu(ContextMenu menu, DropPanel panel)
|
||||
{
|
||||
if (menu.Items.Any(x => x is ContextMenuButton b && b.Text.Equals("Open All", StringComparison.Ordinal)))
|
||||
@@ -695,10 +700,24 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
});
|
||||
}
|
||||
|
||||
private void OnLayoutSizeChanged(Control control)
|
||||
{
|
||||
if (Layout.ContainerControl is DropPanel dropPanel)
|
||||
{
|
||||
// Hide "Size" text when array editor title overlaps
|
||||
var headerTextSize = dropPanel.HeaderTextFont.GetFont().MeasureText(dropPanel.HeaderText);
|
||||
if (headerTextSize.X + DropPanel.DropDownIconSize >= _label.Left)
|
||||
_label.TextColor = _label.TextColorHighlighted = Color.Transparent;
|
||||
else
|
||||
_label.TextColor = _label.TextColorHighlighted = FlaxEngine.GUI.Style.Current.Foreground;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Deinitialize()
|
||||
{
|
||||
_sizeBox = null;
|
||||
Layout.ContainerControl.SizeChanged -= OnLayoutSizeChanged;
|
||||
|
||||
base.Deinitialize();
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ internal class UIControlRefPickerControl : FlaxObjectRefPickerControl
|
||||
/// <inheritdoc />
|
||||
protected override bool IsValid(Object obj)
|
||||
{
|
||||
return obj == null || (obj is UIControl control && control.Control.GetType() == ControlType);
|
||||
return obj == null || (obj is UIControl control && ControlType.IsAssignableFrom(control.Control.GetType()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
// Show prefab diff when reference value type is different
|
||||
var color = Color.Transparent;
|
||||
if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0].GetType() != Values.ReferenceValue.GetType())
|
||||
if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0]?.GetType() != Values.ReferenceValue?.GetType())
|
||||
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
|
||||
_typeItem.Labels[0].HighlightStripColor = color;
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public event Action<TypePickerControl> TypePickerValueChanged;
|
||||
|
||||
/// <summary>
|
||||
/// The custom callback for types validation. Cane be used to implement a rule for types to pick.
|
||||
/// The custom callback for types validation. Can be used to implement a rule for types to pick.
|
||||
/// </summary>
|
||||
public Func<ScriptType, bool> CheckValid;
|
||||
|
||||
@@ -353,7 +353,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
if (!string.IsNullOrEmpty(typeReference.CheckMethod))
|
||||
{
|
||||
var parentType = ParentEditor.Values[0].GetType();
|
||||
var parentEditor = ParentEditor;
|
||||
// Find actual parent editor if parent editor is collection editor
|
||||
while (parentEditor.GetType().IsAssignableTo(typeof(CollectionEditor)))
|
||||
parentEditor = parentEditor.ParentEditor;
|
||||
|
||||
var parentType = parentEditor.Values[0].GetType();
|
||||
|
||||
var method = parentType.GetMethod(typeReference.CheckMethod, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
if (method != null)
|
||||
{
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
{
|
||||
var style = Style.Current;
|
||||
var settingsButtonSize = Panel.HeaderHeight;
|
||||
return new Image
|
||||
Panel.HeaderTextMargin = Panel.HeaderTextMargin with { Right = settingsButtonSize + Utilities.Constants.UIMargin };
|
||||
; return new Image
|
||||
{
|
||||
TooltipText = "Settings",
|
||||
AutoFocus = true,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/ShadowsOfMordor/Builder.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#if PLATFORM_LINUX
|
||||
#include "Engine/Tools/TextureTool/TextureTool.h"
|
||||
@@ -47,6 +48,7 @@ void Editor::CloseSplashScreen()
|
||||
|
||||
bool Editor::CheckProjectUpgrade()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
const auto versionFilePath = Globals::ProjectCacheFolder / TEXT("version");
|
||||
|
||||
// Load version cache file
|
||||
@@ -266,8 +268,8 @@ bool Editor::CheckProjectUpgrade()
|
||||
// Check if last version was older
|
||||
else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR))
|
||||
{
|
||||
LOG(Warning, "The project was opened with the older editor version last time");
|
||||
const auto result = MessageBox::Show(TEXT("The project was opened with the older editor version last time. Loading it may modify existing data so older editor version won't open it. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question);
|
||||
LOG(Warning, "The project was last opened with an older editor version");
|
||||
const auto result = MessageBox::Show(TEXT("The project was last opened with an older editor version.\nLoading it may modify existing data, which can result in older editor versions being unable to open it.\n\nDo you want to perform a backup before or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Question);
|
||||
if (result == DialogResult::Yes)
|
||||
{
|
||||
if (BackupProject())
|
||||
@@ -289,8 +291,8 @@ bool Editor::CheckProjectUpgrade()
|
||||
// Check if last version was newer
|
||||
else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR))
|
||||
{
|
||||
LOG(Warning, "The project was opened with the newer editor version last time");
|
||||
const auto result = MessageBox::Show(TEXT("The project was opened with the newer editor version last time. Loading it may fail and corrupt existing data. Do you want to perform a backup before or cancel operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning);
|
||||
LOG(Warning, "The project was last opened with a newer editor version");
|
||||
const auto result = MessageBox::Show(TEXT("The project was last opened with a newer editor version.\nLoading it may fail and corrupt existing data.\n\nDo you want to perform a backup before loading or cancel the operation?"), TEXT("Project upgrade"), MessageBoxButtons::YesNoCancel, MessageBoxIcon::Warning);
|
||||
if (result == DialogResult::Yes)
|
||||
{
|
||||
if (BackupProject())
|
||||
@@ -366,6 +368,8 @@ bool Editor::BackupProject()
|
||||
|
||||
int32 Editor::LoadProduct()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Flax Editor product
|
||||
Globals::ProductName = TEXT("Flax Editor");
|
||||
Globals::CompanyName = TEXT("Flax");
|
||||
@@ -626,6 +630,7 @@ int32 Editor::LoadProduct()
|
||||
|
||||
Window* Editor::CreateMainWindow()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
Window* window = Managed->GetMainWindow();
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
@@ -662,6 +667,7 @@ bool Editor::Init()
|
||||
return true;
|
||||
}
|
||||
PROFILE_CPU();
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// If during last lightmaps baking engine crashed we could try to restore the progress
|
||||
ShadowsOfMordor::Builder::Instance()->CheckIfRestoreState();
|
||||
@@ -693,11 +699,13 @@ bool Editor::Init()
|
||||
|
||||
void Editor::BeforeRun()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
Managed->BeforeRun();
|
||||
}
|
||||
|
||||
void Editor::BeforeExit()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
CloseSplashScreen();
|
||||
|
||||
Managed->Exit();
|
||||
@@ -708,6 +716,8 @@ void Editor::BeforeExit()
|
||||
|
||||
void EditorImpl::OnUpdate()
|
||||
{
|
||||
PROFILE_MEM(Editor);
|
||||
|
||||
// Update c# editor
|
||||
Editor::Managed->Update();
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ using FlaxEngine.Assertions;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Interop;
|
||||
using FlaxEngine.Json;
|
||||
using FlaxEngine.Utilities;
|
||||
|
||||
#pragma warning disable CS1591
|
||||
|
||||
@@ -51,6 +52,7 @@ namespace FlaxEditor
|
||||
private readonly List<EditorModule> _modules = new List<EditorModule>(16);
|
||||
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit;
|
||||
private string _projectToOpen;
|
||||
private bool _projectIsNew;
|
||||
private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f;
|
||||
private Button _saveNowButton;
|
||||
private Button _cancelSaveButton;
|
||||
@@ -737,11 +739,12 @@ namespace FlaxEditor
|
||||
var procSettings = new CreateProcessSettings
|
||||
{
|
||||
FileName = Platform.ExecutableFilePath,
|
||||
Arguments = string.Format("-project \"{0}\"", _projectToOpen),
|
||||
Arguments = string.Format("-project \"{0}\"" + (_projectIsNew ? " -new" : string.Empty), _projectToOpen),
|
||||
ShellExecute = true,
|
||||
WaitForEnd = false,
|
||||
HiddenWindow = false,
|
||||
};
|
||||
_projectIsNew = false;
|
||||
_projectToOpen = null;
|
||||
Platform.CreateProcess(ref procSettings);
|
||||
}
|
||||
@@ -790,6 +793,24 @@ namespace FlaxEditor
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the given project. Afterwards closes this project with running editor and opens the given project.
|
||||
/// </summary>
|
||||
/// <param name="projectFilePath">The project file path.</param>
|
||||
public void NewProject(string projectFilePath)
|
||||
{
|
||||
if (projectFilePath == null)
|
||||
{
|
||||
MessageBox.Show("Missing project");
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache project path and start editor exit (it will open new instance on valid closing)
|
||||
_projectToOpen = StringUtils.NormalizePath(Path.GetDirectoryName(projectFilePath));
|
||||
_projectIsNew = true;
|
||||
Windows.MainWindow.Close(ClosingReason.User);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Closes this project with running editor and opens the given project.
|
||||
/// </summary>
|
||||
@@ -1350,7 +1371,7 @@ namespace FlaxEditor
|
||||
public void BuildCSG()
|
||||
{
|
||||
var scenes = Level.Scenes;
|
||||
scenes.ToList().ForEach(x => x.BuildCSG(0));
|
||||
scenes.ForEach(x => x.BuildCSG(0));
|
||||
Scene.MarkSceneEdited(scenes);
|
||||
}
|
||||
|
||||
@@ -1360,7 +1381,7 @@ namespace FlaxEditor
|
||||
public void BuildNavMesh()
|
||||
{
|
||||
var scenes = Level.Scenes;
|
||||
scenes.ToList().ForEach(x => Navigation.BuildNavMesh(x, 0));
|
||||
Navigation.BuildNavMesh();
|
||||
Scene.MarkSceneEdited(scenes);
|
||||
}
|
||||
|
||||
@@ -1370,6 +1391,7 @@ namespace FlaxEditor
|
||||
public void BuildAllMeshesSDF()
|
||||
{
|
||||
var models = new List<Model>();
|
||||
var forceRebuild = Input.GetKey(KeyboardKeys.F);
|
||||
Scene.ExecuteOnGraph(node =>
|
||||
{
|
||||
if (node is StaticModelNode staticModelNode && staticModelNode.Actor is StaticModel staticModel)
|
||||
@@ -1379,7 +1401,7 @@ namespace FlaxEditor
|
||||
model != null &&
|
||||
!models.Contains(model) &&
|
||||
!model.IsVirtual &&
|
||||
model.SDF.Texture == null)
|
||||
(forceRebuild || model.SDF.Texture == null))
|
||||
{
|
||||
models.Add(model);
|
||||
}
|
||||
@@ -1392,7 +1414,17 @@ namespace FlaxEditor
|
||||
{
|
||||
var model = models[i];
|
||||
Log($"[{i}/{models.Count}] Generating SDF for {model}");
|
||||
if (!model.GenerateSDF())
|
||||
float resolutionScale = 1.0f, backfacesThreshold = 0.6f;
|
||||
int lodIndex = 6;
|
||||
bool useGPU = true;
|
||||
var sdf = model.SDF;
|
||||
if (sdf.Texture != null)
|
||||
{
|
||||
// Preserve options set on this model
|
||||
resolutionScale = sdf.ResolutionScale;
|
||||
lodIndex = sdf.LOD;
|
||||
}
|
||||
if (!model.GenerateSDF(resolutionScale, lodIndex, true, backfacesThreshold, useGPU))
|
||||
model.Save();
|
||||
}
|
||||
});
|
||||
@@ -1567,7 +1599,7 @@ namespace FlaxEditor
|
||||
if (dockedTo != null && dockedTo.SelectedTab != gameWin && dockedTo.SelectedTab != null)
|
||||
result = dockedTo.SelectedTab.Size;
|
||||
else
|
||||
result = gameWin.Viewport.Size;
|
||||
result = gameWin.Viewport.ContentSize;
|
||||
|
||||
result *= root.DpiScale;
|
||||
result = Float2.Round(result);
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The column title horizontal text alignment
|
||||
/// </summary>
|
||||
public TextAlignment TitleAlignment = TextAlignment.Near;
|
||||
public TextAlignment TitleAlignment = TextAlignment.Center;
|
||||
|
||||
/// <summary>
|
||||
/// The column title margin.
|
||||
|
||||
@@ -502,6 +502,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
if (base.OnKeyDown(key))
|
||||
return true;
|
||||
|
||||
// Keyboard navigation around the menu
|
||||
switch (key)
|
||||
{
|
||||
case KeyboardKeys.ArrowDown:
|
||||
@@ -526,6 +527,20 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KeyboardKeys.ArrowRight:
|
||||
for (int i = 0; i < _panel.Children.Count; i++)
|
||||
{
|
||||
if (_panel.Children[i] is ContextMenuChildMenu item && item.Visible && item.IsFocused && !item.ContextMenu.IsOpened)
|
||||
{
|
||||
item.ShowChild(this);
|
||||
item.ContextMenu._panel.Children.FirstOrDefault(x => x is ContextMenuButton && x.Visible)?.Focus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case KeyboardKeys.ArrowLeft:
|
||||
ParentCM?.RootWindow.Focus();
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -72,6 +72,11 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
/// </summary>
|
||||
public bool HasChildCMOpened => _childCM != null;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the parent context menu (if exists).
|
||||
/// </summary>
|
||||
public ContextMenuBase ParentCM => _parentCM;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the topmost context menu.
|
||||
/// </summary>
|
||||
@@ -81,9 +86,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
{
|
||||
var cm = this;
|
||||
while (cm._parentCM != null && cm._isSubMenu)
|
||||
{
|
||||
cm = cm._parentCM;
|
||||
}
|
||||
return cm;
|
||||
}
|
||||
}
|
||||
@@ -108,15 +111,21 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
/// </summary>
|
||||
public bool UseInput = true;
|
||||
|
||||
/// <summary>
|
||||
/// Optional flag that can disable UI navigation (tab/enter).
|
||||
/// </summary>
|
||||
public bool UseNavigation = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContextMenuBase"/> class.
|
||||
/// </summary>
|
||||
public ContextMenuBase()
|
||||
: base(0, 0, 120, 32)
|
||||
{
|
||||
_direction = ContextMenuDirection.RightDown;
|
||||
Visible = false;
|
||||
AutoFocus = true;
|
||||
|
||||
_direction = ContextMenuDirection.RightDown;
|
||||
_isSubMenu = true;
|
||||
}
|
||||
|
||||
@@ -593,6 +602,21 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
case KeyboardKeys.Escape:
|
||||
Hide();
|
||||
return true;
|
||||
case KeyboardKeys.Return:
|
||||
if (UseNavigation && Root?.FocusedControl != null)
|
||||
{
|
||||
Root.SubmitFocused();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case KeyboardKeys.Tab:
|
||||
if (UseNavigation && Root != null)
|
||||
{
|
||||
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
CloseMenuOnClick = false;
|
||||
}
|
||||
|
||||
private void ShowChild(ContextMenu parentContextMenu)
|
||||
internal void ShowChild(ContextMenu parentContextMenu)
|
||||
{
|
||||
// Hide parent CM popups and set itself as child
|
||||
var vAlign = parentContextMenu.ItemsAreaMargin.Top;
|
||||
|
||||
@@ -522,6 +522,16 @@ namespace FlaxEditor.GUI
|
||||
cm.AddButton("Show whole curve", _editor.ShowWholeCurve);
|
||||
cm.AddButton("Reset view", _editor.ResetView);
|
||||
}
|
||||
cm.AddSeparator();
|
||||
var presetCm = cm.AddChildMenu("Apply preset");
|
||||
foreach (var value in Enum.GetValues(typeof(CurvePreset)))
|
||||
{
|
||||
CurvePreset preset = (CurvePreset)value;
|
||||
string name = Utilities.Utils.GetPropertyNameUI(preset.ToString());
|
||||
var b = presetCm.ContextMenu.AddButton(name, () => _editor.ApplyPreset(preset));
|
||||
b.Enabled = !(_editor is LinearCurveEditor<T> && (preset != CurvePreset.Constant && preset != CurvePreset.Linear));
|
||||
}
|
||||
|
||||
_editor.OnShowContextMenu(cm, selectionCount);
|
||||
cm.Show(this, location);
|
||||
}
|
||||
@@ -619,6 +629,33 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A list of avaliable curve presets for the <see cref="CurveEditor{T}"/>.
|
||||
/// </summary>
|
||||
public enum CurvePreset
|
||||
{
|
||||
/// <summary>
|
||||
/// A curve where every point has the same value.
|
||||
/// </summary>
|
||||
Constant,
|
||||
/// <summary>
|
||||
/// A curve linear curve.
|
||||
/// </summary>
|
||||
Linear,
|
||||
/// <summary>
|
||||
/// A curve that starts a slowly and then accelerates until the end.
|
||||
/// </summary>
|
||||
EaseIn,
|
||||
/// <summary>
|
||||
/// A curve that starts a steep and then flattens until the end.
|
||||
/// </summary>
|
||||
EaseOut,
|
||||
/// <summary>
|
||||
/// A combination of the <see cref="CurvePreset.EaseIn"/> and <see cref="CurvePreset.EaseOut"/> preset.
|
||||
/// </summary>
|
||||
Smoothstep
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnKeyframesDeselect(IKeyframesEditor editor)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,48 @@ namespace FlaxEditor.GUI
|
||||
/// <seealso cref="CurveEditorBase" />
|
||||
public abstract partial class CurveEditor<T> : CurveEditorBase where T : new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single point in a <see cref="CurveEditorPreset"/>.
|
||||
/// </summary>
|
||||
protected struct CurvePresetPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// The time.
|
||||
/// </summary>
|
||||
public float Time;
|
||||
|
||||
/// <summary>
|
||||
/// The value.
|
||||
/// </summary>
|
||||
public float Value;
|
||||
|
||||
/// <summary>
|
||||
/// The in tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
|
||||
/// </summary>
|
||||
public float TangentIn;
|
||||
|
||||
/// <summary>
|
||||
/// The out tangent. Will be ignored in <see cref="LinearCurveEditor{T}"/>
|
||||
/// </summary>
|
||||
public float TangentOut;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A curve preset.
|
||||
/// </summary>
|
||||
protected struct CurveEditorPreset()
|
||||
{
|
||||
/// <summary>
|
||||
/// If the tangents will be linear or smooth.
|
||||
/// </summary>
|
||||
public bool LinearTangents;
|
||||
|
||||
/// <summary>
|
||||
/// The points of the preset.
|
||||
/// </summary>
|
||||
public List<CurvePresetPoint> Points;
|
||||
}
|
||||
|
||||
private class Popup : ContextMenuBase
|
||||
{
|
||||
private CustomEditorPresenter _presenter;
|
||||
@@ -26,11 +68,12 @@ namespace FlaxEditor.GUI
|
||||
private List<int> _keyframeIndices;
|
||||
private bool _isDirty;
|
||||
|
||||
public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float height = 140.0f)
|
||||
: this(editor, height)
|
||||
public Popup(CurveEditor<T> editor, object[] selection, List<int> keyframeIndices = null, float maxHeight = 140.0f)
|
||||
: this(editor, maxHeight)
|
||||
{
|
||||
_presenter.Select(selection);
|
||||
_presenter.OpenAllGroups();
|
||||
Size = new Float2(Size.X, Mathf.Min(_presenter.ContainerControl.Size.Y, maxHeight));
|
||||
_keyframeIndices = keyframeIndices;
|
||||
if (keyframeIndices != null && selection.Length != keyframeIndices.Count)
|
||||
throw new Exception();
|
||||
@@ -169,7 +212,7 @@ namespace FlaxEditor.GUI
|
||||
if (IsSelected)
|
||||
color = Editor.ContainsFocus ? style.SelectionBorder : Color.Lerp(style.ForegroundDisabled, style.SelectionBorder, 0.4f);
|
||||
if (IsMouseOver)
|
||||
color *= 1.1f;
|
||||
color *= 1.5f;
|
||||
Render2D.FillRectangle(rect, color);
|
||||
}
|
||||
|
||||
@@ -285,7 +328,7 @@ namespace FlaxEditor.GUI
|
||||
/// <summary>
|
||||
/// The keyframes size.
|
||||
/// </summary>
|
||||
protected static readonly Float2 KeyframesSize = new Float2(7.0f);
|
||||
protected static readonly Float2 KeyframesSize = new Float2(8.0f);
|
||||
|
||||
/// <summary>
|
||||
/// The colors for the keyframe points.
|
||||
@@ -326,6 +369,63 @@ namespace FlaxEditor.GUI
|
||||
private Color _labelsColor;
|
||||
private Font _labelsFont;
|
||||
|
||||
/// <summary>
|
||||
/// Preset values for <see cref="CurvePreset"/> to be applied to a <see cref="CurveEditor{T}"/>.
|
||||
/// </summary>
|
||||
protected Dictionary<CurvePreset, CurveEditorPreset> Presets = new Dictionary<CurvePreset, CurveEditorPreset>
|
||||
{
|
||||
{ CurvePreset.Constant, new CurveEditorPreset
|
||||
{
|
||||
LinearTangents = true,
|
||||
Points = new List<CurvePresetPoint>
|
||||
{
|
||||
new CurvePresetPoint { Time = 0f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
|
||||
new CurvePresetPoint { Time = 1f, Value = 0.5f, TangentIn = 0f, TangentOut = 0f },
|
||||
}
|
||||
}
|
||||
},
|
||||
{ CurvePreset.EaseIn, new CurveEditorPreset
|
||||
{
|
||||
LinearTangents = false,
|
||||
Points = new List<CurvePresetPoint>
|
||||
{
|
||||
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = -1.4f, TangentOut = 0f },
|
||||
}
|
||||
}
|
||||
},
|
||||
{ CurvePreset.EaseOut, new CurveEditorPreset
|
||||
{
|
||||
LinearTangents = false,
|
||||
Points = new List<CurvePresetPoint>
|
||||
{
|
||||
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 1.4f },
|
||||
}
|
||||
}
|
||||
},
|
||||
{ CurvePreset.Linear, new CurveEditorPreset
|
||||
{
|
||||
LinearTangents = true,
|
||||
Points = new List<CurvePresetPoint>
|
||||
{
|
||||
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||
}
|
||||
}
|
||||
},
|
||||
{ CurvePreset.Smoothstep, new CurveEditorPreset
|
||||
{
|
||||
LinearTangents = false,
|
||||
Points = new List<CurvePresetPoint>
|
||||
{
|
||||
new CurvePresetPoint { Time = 0f, Value = 0f, TangentIn = 0f, TangentOut = 0f },
|
||||
new CurvePresetPoint { Time = 1f, Value = 1f, TangentIn = 0f, TangentOut = 0f },
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The keyframe UI points.
|
||||
/// </summary>
|
||||
@@ -568,6 +668,28 @@ namespace FlaxEditor.GUI
|
||||
/// <param name="indicesToRemove">The list of indices of the keyframes to remove.</param>
|
||||
protected abstract void RemoveKeyframesInternal(HashSet<int> indicesToRemove);
|
||||
|
||||
/// <summary>
|
||||
/// Tries to convert a float to the type of the type wildcard of the curve editor.
|
||||
/// </summary>
|
||||
/// <param name="value">The float.</param>
|
||||
/// <returns>The converted value.</returns>
|
||||
public static object ConvertCurvePresetValueToCurveEditorType(float value)
|
||||
{
|
||||
if (typeof(T) == typeof(Float2))
|
||||
return new Float2(value);
|
||||
if (typeof(T) == typeof(Float3))
|
||||
return new Float3(value);
|
||||
if (typeof(T) == typeof(Float4))
|
||||
return new Float4(value);
|
||||
if (typeof(T) == typeof(Vector2))
|
||||
return new Vector2(value);
|
||||
if (typeof(T) == typeof(Vector3))
|
||||
return new Vector3(value);
|
||||
if (typeof(T) == typeof(Vector4))
|
||||
return new Vector4(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when showing a context menu. Can be used to add custom buttons with actions.
|
||||
/// </summary>
|
||||
@@ -752,6 +874,17 @@ namespace FlaxEditor.GUI
|
||||
ShowCurve(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a <see cref="CurvePreset"/> to the curve editor.
|
||||
/// </summary>
|
||||
/// <param name="preset">The preset.</param>
|
||||
public virtual void ApplyPreset(CurvePreset preset)
|
||||
{
|
||||
// Remove existing keyframes
|
||||
SelectAll();
|
||||
RemoveKeyframes();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Evaluate(out object result, float time, bool loop = false)
|
||||
{
|
||||
@@ -1028,6 +1161,31 @@ namespace FlaxEditor.GUI
|
||||
return true;
|
||||
}
|
||||
|
||||
bool left = key == KeyboardKeys.ArrowLeft;
|
||||
bool right = key == KeyboardKeys.ArrowRight;
|
||||
bool up = key == KeyboardKeys.ArrowUp;
|
||||
bool down = key == KeyboardKeys.ArrowDown;
|
||||
|
||||
if (left || right || up || down)
|
||||
{
|
||||
bool shift = Root.GetKey(KeyboardKeys.Shift);
|
||||
bool alt = Root.GetKey(KeyboardKeys.Alt);
|
||||
float deltaValue = 10f;
|
||||
if (shift || alt)
|
||||
deltaValue = shift ? 2.5f : 5f;
|
||||
|
||||
Float2 moveDelta = Float2.Zero;
|
||||
if (left || right)
|
||||
moveDelta.X = left ? -deltaValue : deltaValue;
|
||||
if (up || down)
|
||||
moveDelta.Y = up ? -deltaValue : deltaValue;
|
||||
|
||||
_contents.OnMoveStart(Float2.Zero);
|
||||
_contents.OnMove(moveDelta);
|
||||
_contents.OnMoveEnd(Float2.Zero);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1526,6 +1684,22 @@ namespace FlaxEditor.GUI
|
||||
_tangents[i].Visible = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ApplyPreset(CurvePreset preset)
|
||||
{
|
||||
base.ApplyPreset(preset);
|
||||
|
||||
CurveEditorPreset data = Presets[preset];
|
||||
foreach (var point in data.Points)
|
||||
{
|
||||
float time = point.Time;
|
||||
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
|
||||
AddKeyframe(time, value);
|
||||
}
|
||||
|
||||
ShowWholeCurve();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void DrawCurve(ref Rectangle viewRect)
|
||||
{
|
||||
@@ -2312,6 +2486,30 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ApplyPreset(CurvePreset preset)
|
||||
{
|
||||
base.ApplyPreset(preset);
|
||||
|
||||
CurveEditorPreset data = Presets[preset];
|
||||
|
||||
foreach (var point in data.Points)
|
||||
{
|
||||
float time = point.Time;
|
||||
object value = ConvertCurvePresetValueToCurveEditorType((float)point.Value);
|
||||
object tangentIn = ConvertCurvePresetValueToCurveEditorType((float)point.TangentIn);
|
||||
object tangentOut = ConvertCurvePresetValueToCurveEditorType((float)point.TangentOut);
|
||||
|
||||
AddKeyframe(time, value, tangentIn, tangentOut);
|
||||
}
|
||||
|
||||
SelectAll();
|
||||
if (data.LinearTangents)
|
||||
SetTangentsLinear();
|
||||
|
||||
ShowWholeCurve();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void SetScaleInternal(ref Float2 scale)
|
||||
{
|
||||
|
||||
@@ -76,6 +76,8 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
public ColorSelector(float wheelSize)
|
||||
: base(0, 0, wheelSize, wheelSize)
|
||||
{
|
||||
AutoFocus = true;
|
||||
|
||||
_colorWheelSprite = Editor.Instance.Icons.ColorWheel128;
|
||||
_wheelRect = new Rectangle(0, 0, wheelSize, wheelSize);
|
||||
}
|
||||
|
||||
@@ -469,7 +469,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
var childPanels = _childPanels.ToArray();
|
||||
if (childPanels.Length != 0)
|
||||
{
|
||||
// Move tabs from child panels into this one
|
||||
// Fallback: move tabs from child panels into this one.
|
||||
DockWindow selectedTab = null;
|
||||
foreach (var childPanel in childPanels)
|
||||
{
|
||||
@@ -490,7 +490,8 @@ namespace FlaxEditor.GUI.Docking
|
||||
{
|
||||
// Unlink splitter
|
||||
var splitterParent = splitter.Parent;
|
||||
Assert.IsNotNull(splitterParent);
|
||||
if (splitterParent == null)
|
||||
return;
|
||||
splitter.Parent = null;
|
||||
|
||||
// Move controls from second split panel to the split panel parent
|
||||
@@ -507,17 +508,63 @@ namespace FlaxEditor.GUI.Docking
|
||||
splitter.Dispose();
|
||||
}
|
||||
}
|
||||
else if (IsMaster && _childPanels.Count != 0)
|
||||
{
|
||||
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
|
||||
return;
|
||||
}
|
||||
else if (!IsMaster)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else if (_childPanels.Count != 0)
|
||||
{
|
||||
if (TryCollapseSplitter(_tabsProxy?.Parent as Panel))
|
||||
return;
|
||||
}
|
||||
else if (!IsMaster)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
internal bool CollapseEmptyTabsProxy()
|
||||
{
|
||||
if (TabsCount == 0 && ChildPanelsCount > 0)
|
||||
{
|
||||
return TryCollapseSplitter(_tabsProxy?.Parent as Panel);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryCollapseSplitter(Panel removedPanelParent)
|
||||
{
|
||||
if (removedPanelParent == null)
|
||||
return false;
|
||||
if (!(removedPanelParent.Parent is SplitPanel tabsSplitter))
|
||||
return false;
|
||||
|
||||
var splitterParent = tabsSplitter.Parent;
|
||||
if (splitterParent == null)
|
||||
return false;
|
||||
tabsSplitter.Parent = null;
|
||||
|
||||
var scrPanel = removedPanelParent == tabsSplitter.Panel2 ? tabsSplitter.Panel1 : tabsSplitter.Panel2;
|
||||
var srcPanelChildrenCount = scrPanel.ChildrenCount;
|
||||
for (int i = srcPanelChildrenCount - 1; i >= 0 && scrPanel.ChildrenCount > 0; i--)
|
||||
{
|
||||
scrPanel.GetChild(i).Parent = splitterParent;
|
||||
}
|
||||
Assert.IsTrue(scrPanel.ChildrenCount == 0);
|
||||
Assert.IsTrue(splitterParent.ChildrenCount == srcPanelChildrenCount);
|
||||
|
||||
tabsSplitter.Dispose();
|
||||
if (_tabsProxy != null && _tabsProxy.Parent == removedPanelParent)
|
||||
_tabsProxy = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
internal virtual void DockWindowInternal(DockState state, DockWindow window, bool autoSelect = true, float? splitterValue = null)
|
||||
{
|
||||
DockWindow(state, window, autoSelect, splitterValue);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user