2 Commits

Author SHA1 Message Date
c6bc90a82a _lagdriver fixes
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-09-12 13:52:55 +03:00
43b576d961 Add support for Visual Studio 2026 and v145 MSVC toolset
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
2025-09-10 20:05:28 +03:00
324 changed files with 2795 additions and 5706 deletions

View File

@@ -1,42 +0,0 @@
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: 2
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

View File

@@ -1,22 +0,0 @@
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

View File

@@ -19,7 +19,7 @@ jobs:
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: 9.0.x dotnet-version: 8.0.x
- name: Setup .NET Workload - name: Setup .NET Workload
run: | run: |
dotnet workload install ios dotnet workload install ios
@@ -33,4 +33,4 @@ jobs:
git lfs pull git lfs pull
- name: Build - name: Build
run: | run: |
./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=9 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame ./Development/Scripts/Mac/CallBuildTool.sh -build -log -dotnet=8 -arch=ARM64 -platform=iOS -configuration=Release -buildtargets=FlaxGame

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

BIN
Content/Editor/Gizmo/MaterialAxisLocked.flax (Stored with Git LFS) Normal file

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

View File

@@ -6,7 +6,6 @@
@3 @3
#include "./Flax/Common.hlsl" #include "./Flax/Common.hlsl"
#include "./Flax/Stencil.hlsl"
#include "./Flax/MaterialCommon.hlsl" #include "./Flax/MaterialCommon.hlsl"
#include "./Flax/GBufferCommon.hlsl" #include "./Flax/GBufferCommon.hlsl"
@7 @7
@@ -15,13 +14,10 @@ META_CB_BEGIN(0, Data)
float4x4 WorldMatrix; float4x4 WorldMatrix;
float4x4 InvWorld; float4x4 InvWorld;
float4x4 SvPositionToWorld; float4x4 SvPositionToWorld;
float3 Padding0;
uint RenderLayersMask;
@1META_CB_END @1META_CB_END
// Use depth buffer for per-pixel decal layering // Use depth buffer for per-pixel decal layering
Texture2D DepthBuffer : register(t0); Texture2D DepthBuffer : register(t0);
Texture2D<uint2> StencilBuffer : register(t1);
// Material shader resources // Material shader resources
@2 @2
@@ -204,14 +200,6 @@ void PS_Decal(
#endif #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; float2 screenUV = SvPosition.xy * ScreenSize.zw;
SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r; SvPosition.z = SAMPLE_RT(DepthBuffer, screenUV).r;

View File

@@ -27,7 +27,6 @@ TextureCube EnvProbe : register(t__SRV__);
TextureCube SkyLightTexture : register(t__SRV__); TextureCube SkyLightTexture : register(t__SRV__);
Buffer<float4> ShadowsBuffer : register(t__SRV__); Buffer<float4> ShadowsBuffer : register(t__SRV__);
Texture2D<float> ShadowMap : register(t__SRV__); Texture2D<float> ShadowMap : register(t__SRV__);
Texture3D VolumetricFogTexture : register(t__SRV__);
@4// Forward Shading: Utilities @4// Forward Shading: Utilities
// Public accessors for lighting data, use them as data binding might change but those methods will remain. // Public accessors for lighting data, use them as data binding might change but those methods will remain.
LightData GetDirectionalLight() { return DirectionalLight; } LightData GetDirectionalLight() { return DirectionalLight; }
@@ -152,25 +151,7 @@ void PS_Forward(
#if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT #if USE_FOG && MATERIAL_SHADING_MODEL != SHADING_MODEL_UNLIT
// Calculate exponential height fog // Calculate exponential height fog
#if DIRECTX && FEATURE_LEVEL < FEATURE_LEVEL_SM6 float4 fog = GetExponentialHeightFog(ExponentialHeightFog, materialInput.WorldPosition, ViewPos, 0, gBuffer.ViewPos.z);
// 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 // Apply fog to the output color
#if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE #if MATERIAL_BLEND == MATERIAL_BLEND_OPAQUE

View File

@@ -21,7 +21,7 @@ float4 ViewInfo;
float4 ScreenSize; float4 ScreenSize;
float4 ViewSize; float4 ViewSize;
float3 ViewPadding0; float3 ViewPadding0;
float ScaledTimeParam; float UnscaledTimeParam;
@1META_CB_END @1META_CB_END
// Shader resources // Shader resources

View File

@@ -645,7 +645,7 @@ VertexOutput VS_Ribbon(RibbonInput input, uint vertexIndex : SV_VertexID)
materialInput.TBN = output.TBN; materialInput.TBN = output.TBN;
materialInput.TwoSidedSign = 1; materialInput.TwoSidedSign = 1;
materialInput.SvPosition = output.Position; materialInput.SvPosition = output.Position;
materialInput.PreSkinnedPosition = position; materialInput.PreSkinnedPosition = Position;
materialInput.PreSkinnedNormal = tangentToLocal[2].xyz; materialInput.PreSkinnedNormal = tangentToLocal[2].xyz;
materialInput.InstanceOrigin = output.InstanceOrigin; materialInput.InstanceOrigin = output.InstanceOrigin;
materialInput.InstanceParams = output.InstanceParams; materialInput.InstanceParams = output.InstanceParams;

View File

@@ -20,7 +20,7 @@ float4 ScreenSize;
float4 TemporalAAJitter; float4 TemporalAAJitter;
float4x4 InverseViewProjectionMatrix; float4x4 InverseViewProjectionMatrix;
float3 ViewPadding0; float3 ViewPadding0;
float ScaledTimeParam; float UnscaledTimeParam;
@1META_CB_END @1META_CB_END
// Shader resources // Shader resources

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

View File

@@ -4,7 +4,7 @@
"Major": 1, "Major": 1,
"Minor": 11, "Minor": 11,
"Revision": 0, "Revision": 0,
"Build": 6801 "Build": 6800
}, },
"Company": "Flax", "Company": "Flax",
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.", "Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",

19
ISSUE_TEMPLATE.md Normal file
View File

@@ -0,0 +1,19 @@
<!-- 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. -->

View File

@@ -117,8 +117,7 @@ namespace FlaxEditor.Content.Create
private static bool IsValid(Type type) private static bool IsValid(Type type)
{ {
var controlTypes = Editor.Instance.CodeEditing.Controls.Get(); return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType;
return (type.IsPublic || type.IsNestedPublic) && !type.IsAbstract && !type.IsGenericType && controlTypes.Contains(new ScriptType(type));
} }
} }

View File

@@ -87,11 +87,8 @@ namespace FlaxEditor.CustomEditors
var targetTypeType = TypeUtils.GetType(targetType); var targetTypeType = TypeUtils.GetType(targetType);
if (canUseRefPicker) if (canUseRefPicker)
{ {
// TODO: add generic way of CustomEditor for ref pickers (use it on AssetRefEditor/GPUTextureEditor/...)
if (typeof(Asset).IsAssignableFrom(targetTypeType)) if (typeof(Asset).IsAssignableFrom(targetTypeType))
return new AssetRefEditor(); return new AssetRefEditor();
if (typeof(GPUTexture).IsAssignableFrom(targetTypeType))
return new GPUTextureEditor();
if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType)) if (typeof(FlaxEngine.Object).IsAssignableFrom(targetTypeType))
return new FlaxObjectRefEditor(); return new FlaxObjectRefEditor();
} }

View File

@@ -13,8 +13,6 @@ namespace FlaxEditor.CustomEditors.Dedicated
public class AudioSourceEditor : ActorEditor public class AudioSourceEditor : ActorEditor
{ {
private Label _infoLabel; private Label _infoLabel;
private Slider _slider;
private AudioSource.States _slideStartState;
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
@@ -30,13 +28,6 @@ namespace FlaxEditor.CustomEditors.Dedicated
_infoLabel = playbackGroup.Label(string.Empty).Label; _infoLabel = playbackGroup.Label(string.Empty).Label;
_infoLabel.AutoHeight = true; _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 grid = playbackGroup.UniformGrid();
var gridControl = grid.CustomControl; var gridControl = grid.CustomControl;
gridControl.ClipChildren = false; gridControl.ClipChildren = false;
@@ -49,38 +40,6 @@ 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 /> /// <inheritdoc />
public override void Refresh() public override void Refresh()
{ {
@@ -92,29 +51,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
foreach (var value in Values) foreach (var value in Values)
{ {
if (value is AudioSource audioSource && audioSource.Clip) if (value is AudioSource audioSource && audioSource.Clip)
{
text += $"Time: {audioSource.Time:##0.0}s / {audioSource.Clip.Length:##0.0}s\n"; 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; _infoLabel.Text = text;
} }

View File

@@ -1,68 +0,0 @@
// Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.GUI.ContextMenu;
using FlaxEngine;
using FlaxEngine.GUI;
namespace FlaxEditor.CustomEditors.Dedicated
{
/// <summary>
/// Basic editor/viewer for <see cref="GPUTexture"/>.
/// </summary>
[CustomEditor(typeof(GPUTexture)), DefaultEditor]
public class GPUTextureEditor : CustomEditor
{
private Image _image;
/// <inheritdoc />
public override DisplayStyle Style => DisplayStyle.Inline;
/// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout)
{
_image = new Image
{
Brush = new GPUTextureBrush(),
Size = new Float2(200, 100),
Parent = layout.ContainerControl,
};
_image.Clicked += OnImageClicked;
}
private void OnImageClicked(Image image, MouseButton button)
{
var texture = Values[0] as GPUTexture;
if (!texture || button != MouseButton.Right)
return;
var menu = new ContextMenu();
menu.AddButton("Save...", () => Screenshot.Capture(Values[0] as GPUTexture));
menu.AddButton("Enlarge", () => _image.Size *= 2);
menu.AddButton("Shrink", () => _image.Size /= 2).Enabled = _image.Height > 32;
var location = image.PointFromScreen(Input.MouseScreenPosition);
menu.Show(image, location);
}
/// <inheritdoc />
public override void Refresh()
{
base.Refresh();
var texture = Values[0] as GPUTexture;
((GPUTextureBrush)_image.Brush).Texture = texture;
if (texture)
{
var desc = texture.Description;
#if BUILD_RELEASE
var name = string.Empty;
#else
var name = texture.Name;
#endif
_image.TooltipText = $"{name}\nType: {texture.ResourceType}\nSize: {desc.Width}x{desc.Height}\nFormat: {desc.Format}\nMemory: {Utilities.Utils.FormatBytesCount(texture.MemoryUsage)}";
}
else
{
_image.TooltipText = "None";
}
}
}
}

View File

@@ -36,7 +36,6 @@ namespace FlaxEditor.CustomEditors.Dedicated
{ {
ScriptName = scriptName; ScriptName = scriptName;
TooltipText = "Create a new script"; TooltipText = "Create a new script";
DrawHighlights = false;
} }
} }
@@ -71,7 +70,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4; var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4;
_addScriptsButton = new Button _addScriptsButton = new Button
{ {
TooltipText = "Add new scripts to the actor.", TooltipText = "Add new scripts to the actor",
AnchorPreset = AnchorPresets.MiddleCenter, AnchorPreset = AnchorPresets.MiddleCenter,
Text = buttonText, Text = buttonText,
Parent = this, Parent = this,
@@ -115,16 +114,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
cm.TextChanged += text => cm.TextChanged += text =>
{ {
if (!IsValidScriptName(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; return;
}
if (!cm.ItemsPanel.Children.Any(x => x.Visible && x is not NewScriptItem)) 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 // 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
@@ -886,7 +876,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
// Add drag button to the group // Add drag button to the group
var scriptDrag = new DragImage var scriptDrag = new DragImage
{ {
TooltipText = "Script reference.", TooltipText = "Script reference",
AutoFocus = true, AutoFocus = true,
IsScrollable = false, IsScrollable = false,
Color = FlaxEngine.GUI.Style.Current.ForegroundGrey, Color = FlaxEngine.GUI.Style.Current.ForegroundGrey,

View File

@@ -71,7 +71,7 @@ namespace FlaxEditor.CustomEditors.Editors
menu.AddButton("Copy", linkedEditor.Copy); menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index)); var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize; b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
b = menu.AddButton("Paste", linkedEditor.Paste); b = menu.AddButton("Paste", linkedEditor.Paste);
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly; b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
@@ -407,7 +407,7 @@ namespace FlaxEditor.CustomEditors.Editors
menu.AddButton("Copy", linkedEditor.Copy); menu.AddButton("Copy", linkedEditor.Copy);
var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index)); var b = menu.AddButton("Duplicate", () => Editor.Duplicate(Index));
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly && Editor._canResize; b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
var paste = menu.AddButton("Paste", linkedEditor.Paste); var paste = menu.AddButton("Paste", linkedEditor.Paste);
paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly; paste.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
@@ -422,8 +422,7 @@ namespace FlaxEditor.CustomEditors.Editors
moveDownButton.Enabled = Index + 1 < Editor.Count; moveDownButton.Enabled = Index + 1 < Editor.Count;
} }
b = menu.AddButton("Remove", OnRemoveClicked); menu.AddButton("Remove", OnRemoveClicked);
b.Enabled = !Editor._readOnly && Editor._canResize;
menu.Show(panel, location); menu.Show(panel, location);
} }

View File

@@ -3,7 +3,6 @@
using System; using System;
using FlaxEditor.GUI; using FlaxEditor.GUI;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.CustomEditors.Editors namespace FlaxEditor.CustomEditors.Editors
@@ -82,13 +81,9 @@ namespace FlaxEditor.CustomEditors.Editors
private OptionType[] _options; private OptionType[] _options;
private ScriptType _type; private ScriptType _type;
private Elements.PropertiesListElement _typeItem;
private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]); private ScriptType Type => Values[0] == null ? Values.Type : TypeUtils.GetObjectType(Values[0]);
/// <inheritdoc />
public override bool RevertValueWithChildren => false; // Always revert value for a whole object
/// <inheritdoc /> /// <inheritdoc />
public override void Initialize(LayoutElementsContainer layout) public override void Initialize(LayoutElementsContainer layout)
{ {
@@ -103,8 +98,7 @@ namespace FlaxEditor.CustomEditors.Editors
_type = type; _type = type;
// Type // Type
_typeItem = layout.AddPropertyItem(TypeComboBoxName, "Type of the object value. Use it to change the object."); var typeEditor = layout.ComboBox(TypeComboBoxName, "Type of the object value. Use it to change the object.");
var typeEditor = _typeItem.ComboBox();
for (int i = 0; i < _options.Length; i++) for (int i = 0; i < _options.Length; i++)
{ {
typeEditor.ComboBox.AddItem(_options[i].Name); typeEditor.ComboBox.AddItem(_options[i].Name);
@@ -132,8 +126,6 @@ namespace FlaxEditor.CustomEditors.Editors
// Value // Value
var values = new CustomValueContainer(type, (instance, index) => instance); var values = new CustomValueContainer(type, (instance, index) => instance);
if (Values.HasReferenceValue)
values.SetReferenceValue(Values.ReferenceValue);
values.AddRange(Values); values.AddRange(Values);
var editor = CustomEditorsUtil.CreateEditor(type); var editor = CustomEditorsUtil.CreateEditor(type);
var style = editor.Style; var style = editor.Style;
@@ -178,12 +170,6 @@ namespace FlaxEditor.CustomEditors.Editors
{ {
base.Refresh(); base.Refresh();
// Show prefab diff when reference value type is different
var color = Color.Transparent;
if (Values.HasReferenceValue && CanRevertReferenceValue && Values[0]?.GetType() != Values.ReferenceValue?.GetType())
color = FlaxEngine.GUI.Style.Current.BackgroundSelected;
_typeItem.Labels[0].HighlightStripColor = color;
// Check if type has been modified outside the editor (eg. from code) // Check if type has been modified outside the editor (eg. from code)
if (Type != _type) if (Type != _type)
{ {

View File

@@ -268,8 +268,8 @@ bool Editor::CheckProjectUpgrade()
// Check if last version was older // Check if last version was older
else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR)) else if (lastVersion.Major < FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor < FLAXENGINE_VERSION_MINOR))
{ {
LOG(Warning, "The project was last opened with an older editor version"); LOG(Warning, "The project was opened with the older editor version last time");
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); 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);
if (result == DialogResult::Yes) if (result == DialogResult::Yes)
{ {
if (BackupProject()) if (BackupProject())
@@ -291,8 +291,8 @@ bool Editor::CheckProjectUpgrade()
// Check if last version was newer // Check if last version was newer
else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR)) else if (lastVersion.Major > FLAXENGINE_VERSION_MAJOR || (lastVersion.Major == FLAXENGINE_VERSION_MAJOR && lastVersion.Minor > FLAXENGINE_VERSION_MINOR))
{ {
LOG(Warning, "The project was last opened with a newer editor version"); LOG(Warning, "The project was opened with the newer editor version last time");
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); 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);
if (result == DialogResult::Yes) if (result == DialogResult::Yes)
{ {
if (BackupProject()) if (BackupProject())

View File

@@ -51,7 +51,6 @@ namespace FlaxEditor
private readonly List<EditorModule> _modules = new List<EditorModule>(16); private readonly List<EditorModule> _modules = new List<EditorModule>(16);
private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit; private bool _isAfterInit, _areModulesInited, _areModulesAfterInitEnd, _isHeadlessMode, _autoExit;
private string _projectToOpen; private string _projectToOpen;
private bool _projectIsNew;
private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f; private float _lastAutoSaveTimer, _autoExitTimeout = 0.1f;
private Button _saveNowButton; private Button _saveNowButton;
private Button _cancelSaveButton; private Button _cancelSaveButton;
@@ -738,12 +737,11 @@ namespace FlaxEditor
var procSettings = new CreateProcessSettings var procSettings = new CreateProcessSettings
{ {
FileName = Platform.ExecutableFilePath, FileName = Platform.ExecutableFilePath,
Arguments = string.Format("-project \"{0}\"" + (_projectIsNew ? " -new" : string.Empty), _projectToOpen), Arguments = string.Format("-project \"{0}\"", _projectToOpen),
ShellExecute = true, ShellExecute = true,
WaitForEnd = false, WaitForEnd = false,
HiddenWindow = false, HiddenWindow = false,
}; };
_projectIsNew = false;
_projectToOpen = null; _projectToOpen = null;
Platform.CreateProcess(ref procSettings); Platform.CreateProcess(ref procSettings);
} }
@@ -792,24 +790,6 @@ 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> /// <summary>
/// Closes this project with running editor and opens the given project. /// Closes this project with running editor and opens the given project.
/// </summary> /// </summary>

View File

@@ -129,39 +129,11 @@ namespace FlaxEditor.GUI.Input
{ {
base.Draw(); base.Draw();
bool isTransparent = _value.A < 1;
var style = Style.Current; var style = Style.Current;
var fullRect = new Rectangle(0, 0, Width, Height); var r = new Rectangle(0, 0, Width, Height);
var colorRect = new Rectangle(0, 0, isTransparent ? Width * 0.7f : Width, Height);
if (isTransparent) Render2D.FillRectangle(r, _value);
{ Render2D.DrawRectangle(r, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
var alphaRect = new Rectangle(colorRect.Right, 0, Width - colorRect.Right, Height);
// Draw checkerboard pattern to part of the color value box
Render2D.FillRectangle(alphaRect, Color.White);
var smallRectSize = 7.9f;
var numHor = Mathf.CeilToInt(alphaRect.Width / smallRectSize);
var numVer = Mathf.CeilToInt(alphaRect.Height / smallRectSize);
for (int i = 0; i < numHor; i++)
{
for (int j = 0; j < numVer; j++)
{
if ((i + j) % 2 == 0)
{
var rect = new Rectangle(alphaRect.X + smallRectSize * i, alphaRect.Y + smallRectSize * j, new Float2(smallRectSize));
Render2D.PushClip(alphaRect);
Render2D.FillRectangle(rect, Color.Gray);
Render2D.PopClip();
}
}
}
Render2D.FillRectangle(alphaRect, _value);
}
Render2D.FillRectangle(colorRect, _value with { A = 1 });
Render2D.DrawRectangle(fullRect, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -51,11 +51,6 @@ namespace FlaxEditor.GUI
/// </summary> /// </summary>
public float SortScore; public float SortScore;
/// <summary>
/// Wether the query highlights should be draw.
/// </summary>
public bool DrawHighlights = true;
/// <summary> /// <summary>
/// Occurs when items gets clicked by the user. /// Occurs when items gets clicked by the user.
/// </summary> /// </summary>
@@ -170,7 +165,7 @@ namespace FlaxEditor.GUI
Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted); Render2D.FillRectangle(new Rectangle(Float2.Zero, Size), style.BackgroundHighlighted);
// Draw all highlights // Draw all highlights
if (DrawHighlights && _highlights != null) if (_highlights != null)
{ {
var color = style.ProgressNormal * 0.6f; var color = style.ProgressNormal * 0.6f;
for (int i = 0; i < _highlights.Count; i++) for (int i = 0; i < _highlights.Count; i++)

View File

@@ -10,7 +10,6 @@ using System.Text;
using FlaxEditor.GUI.Timeline.Undo; using FlaxEditor.GUI.Timeline.Undo;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json;
using FlaxEngine.Utilities; using FlaxEngine.Utilities;
namespace FlaxEditor.GUI.Timeline.Tracks namespace FlaxEditor.GUI.Timeline.Tracks
@@ -55,10 +54,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var paramTypeName = LoadName(stream); var paramTypeName = LoadName(stream);
e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName); e.EventParamsTypes[i] = TypeUtils.GetManagedType(paramTypeName);
if (e.EventParamsTypes[i] == null) if (e.EventParamsTypes[i] == null)
{
Editor.LogError($"Unknown type {paramTypeName}.");
isInvalid = true; isInvalid = true;
}
} }
if (isInvalid) if (isInvalid)
@@ -86,7 +82,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++) for (int j = 0; j < paramsCount; j++)
{ {
stream.Read(dataBuffer, 0, e.EventParamsSizes[j]); stream.Read(dataBuffer, 0, e.EventParamsSizes[j]);
key.Parameters[j] = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j], e.EventParamsSizes[j]); key.Parameters[j] = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), e.EventParamsTypes[j]);
} }
events[i] = new KeyframesEditor.Keyframe events[i] = new KeyframesEditor.Keyframe
@@ -129,7 +125,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int j = 0; j < paramsCount; j++) for (int j = 0; j < paramsCount; j++)
{ {
Utilities.Utils.StructureToByteArray(key.Parameters[j], e.EventParamsSizes[j], ptr, dataBuffer); Marshal.StructureToPtr(key.Parameters[j], ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.EventParamsSizes[j]);
stream.Write(dataBuffer, 0, e.EventParamsSizes[j]); stream.Write(dataBuffer, 0, e.EventParamsSizes[j]);
} }
} }
@@ -156,7 +153,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
/// <summary> /// <summary>
/// The event key data. /// The event key data.
/// </summary> /// </summary>
public struct EventKey : ICloneable public struct EventKey
{ {
/// <summary> /// <summary>
/// The parameters values. /// The parameters values.
@@ -181,26 +178,6 @@ namespace FlaxEditor.GUI.Timeline.Tracks
sb.Append(')'); sb.Append(')');
return sb.ToString(); return sb.ToString();
} }
/// <inheritdoc />
public object Clone()
{
if (Parameters == null)
return new EventKey();
// Deep clone parameter values (especially boxed value types need to be duplicated to avoid referencing the same ones)
var parameters = new object[Parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
var p = Parameters[i];
if (p == null || p is FlaxEngine.Object)
parameters[i] = Parameters[i];
else
parameters[i] = JsonSerializer.Deserialize(JsonSerializer.Serialize(p), p.GetType());
}
return new EventKey { Parameters = parameters };
}
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -257,7 +234,6 @@ namespace FlaxEditor.GUI.Timeline.Tracks
var time = Timeline.CurrentTime; var time = Timeline.CurrentTime;
if (!TryGetValue(out var value)) if (!TryGetValue(out var value))
value = Events.Evaluate(time); value = Events.Evaluate(time);
value = ((ICloneable)value).Clone();
// Find event at the current location // Find event at the current location
for (int i = Events.Keyframes.Count - 1; i >= 0; i--) for (int i = Events.Keyframes.Count - 1; i >= 0; i--)

View File

@@ -77,7 +77,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
{ {
var time = stream.ReadSingle(); var time = stream.ReadSingle();
stream.Read(dataBuffer, 0, e.ValueSize); stream.Read(dataBuffer, 0, e.ValueSize);
var value = Utilities.Utils.ByteArrayToStructure(handle.AddrOfPinnedObject(), propertyType, e.ValueSize); var value = Marshal.PtrToStructure(handle.AddrOfPinnedObject(), propertyType);
keyframes[i] = new KeyframesEditor.Keyframe keyframes[i] = new KeyframesEditor.Keyframe
{ {
@@ -142,7 +142,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
for (int i = 0; i < keyframes.Count; i++) for (int i = 0; i < keyframes.Count; i++)
{ {
var keyframe = keyframes[i]; var keyframe = keyframes[i];
Utilities.Utils.StructureToByteArray(keyframe.Value, e.ValueSize, ptr, dataBuffer); Marshal.StructureToPtr(keyframe.Value, ptr, true);
Marshal.Copy(ptr, dataBuffer, 0, e.ValueSize);
stream.Write(keyframe.Time); stream.Write(keyframe.Time);
stream.Write(dataBuffer); stream.Write(dataBuffer);
} }

View File

@@ -1,7 +1,9 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using FlaxEditor.Options; using FlaxEditor.Options;
using FlaxEditor.SceneGraph;
using FlaxEngine; using FlaxEngine;
using System;
namespace FlaxEditor.Gizmo namespace FlaxEditor.Gizmo
{ {
@@ -19,16 +21,12 @@ namespace FlaxEditor.Gizmo
private MaterialInstance _materialAxisY; private MaterialInstance _materialAxisY;
private MaterialInstance _materialAxisZ; private MaterialInstance _materialAxisZ;
private MaterialInstance _materialAxisFocus; private MaterialInstance _materialAxisFocus;
private MaterialInstance _materialAxisLocked;
private MaterialBase _materialSphere; private MaterialBase _materialSphere;
// Material Parameter Names // Material Parameter Names
private const string _brightnessParamName = "Brightness"; const String _brightnessParamName = "Brightness";
private const string _opacityParamName = "Opacity"; const String _opacityParamName = "Opacity";
/// <summary>
/// Used for example when the selection can't be moved because one actor is static.
/// </summary>
private bool _isDisabled;
private void InitDrawing() private void InitDrawing()
{ {
@@ -44,6 +42,7 @@ namespace FlaxEditor.Gizmo
_materialAxisY = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisY"); _materialAxisY = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisY");
_materialAxisZ = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisZ"); _materialAxisZ = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisZ");
_materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisFocus"); _materialAxisFocus = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisFocus");
_materialAxisLocked = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialAxisLocked");
_materialSphere = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialSphere"); _materialSphere = FlaxEngine.Content.LoadAsyncInternal<MaterialInstance>("Editor/Gizmo/MaterialSphere");
// Ensure that every asset was loaded // Ensure that every asset was loaded
@@ -68,42 +67,17 @@ namespace FlaxEditor.Gizmo
private void OnEditorOptionsChanged(EditorOptions options) private void OnEditorOptionsChanged(EditorOptions options)
{ {
UpdateGizmoBrightness(options); float brightness = options.Visual.TransformGizmoBrightness;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
_materialAxisLocked.SetParameterValue(_brightnessParamName, brightness);
float opacity = options.Visual.TransformGizmoOpacity; float opacity = options.Visual.TransformGizmoOpacity;
_materialAxisX.SetParameterValue(_opacityParamName, opacity); _materialAxisX.SetParameterValue(_opacityParamName, opacity);
_materialAxisY.SetParameterValue(_opacityParamName, opacity); _materialAxisY.SetParameterValue(_opacityParamName, opacity);
_materialAxisZ.SetParameterValue(_opacityParamName, opacity); _materialAxisZ.SetParameterValue(_opacityParamName, opacity);
} _materialAxisLocked.SetParameterValue(_opacityParamName, opacity);
private void UpdateGizmoBrightness(EditorOptions options)
{
_isDisabled = ShouldGizmoBeLocked();
float brightness = _isDisabled ? options.Visual.TransformGizmoBrightnessDisabled : options.Visual.TransformGizmoBrightness;
if (Mathf.NearEqual(brightness, (float)_materialAxisX.GetParameterValue(_brightnessParamName)))
return;
_materialAxisX.SetParameterValue(_brightnessParamName, brightness);
_materialAxisY.SetParameterValue(_brightnessParamName, brightness);
_materialAxisZ.SetParameterValue(_brightnessParamName, brightness);
}
private bool ShouldGizmoBeLocked()
{
bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode && Owner is Viewport.EditorGizmoViewport)
{
// Block editing static scene objects in main view during play mode
foreach (var obj in Editor.Instance.SceneEditing.Selection)
{
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
return gizmoLocked;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -114,8 +88,20 @@ namespace FlaxEditor.Gizmo
if (!_modelCube || !_modelCube.IsLoaded) if (!_modelCube || !_modelCube.IsLoaded)
return; return;
// Update the gizmo brightness every frame to ensure it updates correctly // Find out if any of the selected objects can not be moved
UpdateGizmoBrightness(Editor.Instance.Options.Options); bool gizmoLocked = false;
if (Editor.Instance.StateMachine.IsPlayMode)
{
for (int i = 0; i < SelectionCount; i++)
{
var obj = GetSelectedObject(i);
if (obj.CanTransform == false)
{
gizmoLocked = true;
break;
}
}
}
// As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order // As all axisMesh have the same pivot, add a little offset to the x axisMesh, this way SortDrawCalls is able to sort the draw order
// https://github.com/FlaxEngine/FlaxEngine/issues/680 // https://github.com/FlaxEngine/FlaxEngine/issues/680
@@ -150,37 +136,37 @@ namespace FlaxEditor.Gizmo
// X axis // X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialTransform = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; MaterialInstance xAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); transAxisMesh.Draw(ref renderContext, xAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialTransform = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; MaterialInstance yAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); transAxisMesh.Draw(ref renderContext, yAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(Mathf.Pi, out m2); Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialTransform = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; MaterialInstance zAxisMaterialTransform = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); transAxisMesh.Draw(ref renderContext, zAxisMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane // XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialTransform = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX; MaterialInstance xyPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, xyPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane // ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialTransform = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisY; MaterialInstance zxPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisY);
cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, zxPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane // YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialTransform = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; MaterialInstance yzPlaneMaterialTransform = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisZ);
cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, yzPlaneMaterialTransform, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center sphere // Center sphere
@@ -200,17 +186,17 @@ namespace FlaxEditor.Gizmo
// X axis // X axis
Matrix.RotationZ(Mathf.PiOverTwo, out m2); Matrix.RotationZ(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); rotationAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); rotationAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m1, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(-Mathf.PiOverTwo, out m2); Matrix.RotationX(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); rotationAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box // Center box
@@ -230,37 +216,37 @@ namespace FlaxEditor.Gizmo
// X axis // X axis
Matrix.RotationY(-Mathf.PiOverTwo, out m2); Matrix.RotationY(-Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref mx1, out m3); Matrix.Multiply(ref m2, ref mx1, out m3);
MaterialInstance xAxisMaterialRotate = (isXAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisX; MaterialInstance xAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isXAxis ? _materialAxisFocus : _materialAxisX);
scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); scaleAxisMesh.Draw(ref renderContext, xAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Y axis // Y axis
Matrix.RotationX(Mathf.PiOverTwo, out m2); Matrix.RotationX(Mathf.PiOverTwo, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yAxisMaterialRotate = (isYAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisY; MaterialInstance yAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isYAxis ? _materialAxisFocus : _materialAxisY);
scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); scaleAxisMesh.Draw(ref renderContext, yAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Z axis // Z axis
Matrix.RotationX(Mathf.Pi, out m2); Matrix.RotationX(Mathf.Pi, out m2);
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zAxisMaterialRotate = (isZAxis && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; MaterialInstance zAxisMaterialRotate = gizmoLocked ? _materialAxisLocked : (isZAxis ? _materialAxisFocus : _materialAxisZ);
scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); scaleAxisMesh.Draw(ref renderContext, zAxisMaterialRotate, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// XY plane // XY plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationX(Mathf.PiOverTwo), new Vector3(boxSize * boxScale, boxSize * boxScale, 0.0f));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance xyPlaneMaterialScale = (_activeAxis == Axis.XY && !_isDisabled) ? _materialAxisFocus : _materialAxisX; MaterialInstance xyPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.XY ? _materialAxisFocus : _materialAxisX);
cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, xyPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// ZX plane // ZX plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.Identity, new Vector3(boxSize * boxScale, 0.0f, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance zxPlaneMaterialScale = (_activeAxis == Axis.ZX && !_isDisabled) ? _materialAxisFocus : _materialAxisZ; MaterialInstance zxPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.ZX ? _materialAxisFocus : _materialAxisZ);
cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, zxPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// YZ plane // YZ plane
m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale)); m2 = Matrix.Transformation(new Vector3(boxSize, boxSize * 0.1f, boxSize), Quaternion.RotationZ(Mathf.PiOverTwo), new Vector3(0.0f, boxSize * boxScale, boxSize * boxScale));
Matrix.Multiply(ref m2, ref m1, out m3); Matrix.Multiply(ref m2, ref m1, out m3);
MaterialInstance yzPlaneMaterialScale = (_activeAxis == Axis.YZ && !_isDisabled) ? _materialAxisFocus : _materialAxisY; MaterialInstance yzPlaneMaterialScale = gizmoLocked ? _materialAxisLocked : (_activeAxis == Axis.YZ ? _materialAxisFocus : _materialAxisY);
cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder); cubeMesh.Draw(ref renderContext, yzPlaneMaterialScale, ref m3, StaticFlags.None, true, DrawPass.Default, 0.0f, sortOrder);
// Center box // Center box

View File

@@ -155,16 +155,6 @@ namespace FlaxEditor
private List<Widget> _widgets; private List<Widget> _widgets;
private Widget _activeWidget; private Widget _activeWidget;
/// <summary>
/// Sets the view size.
/// </summary>
/// <param name="size">The new size.</param>
public void SetViewSize(Float2 size)
{
_view.Size = size;
_view.PerformLayout();
}
/// <summary> /// <summary>
/// True if enable displaying UI editing background and grid elements. /// True if enable displaying UI editing background and grid elements.
/// </summary> /// </summary>

View File

@@ -673,7 +673,6 @@ namespace FlaxEditor.Modules
pasteAction.Do(out _, out var nodeParents); pasteAction.Do(out _, out var nodeParents);
// Select spawned objects (parents only) // Select spawned objects (parents only)
newSelection.Clear();
newSelection.AddRange(nodeParents); newSelection.AddRange(nodeParents);
var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo); var selectAction = new SelectionChangeAction(Selection.ToArray(), newSelection.ToArray(), OnSelectionUndo);
selectAction.Do(); selectAction.Do();

View File

@@ -70,53 +70,6 @@ namespace FlaxEditor.Modules
private bool _progressFailed; private bool _progressFailed;
ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>(); ContextMenuSingleSelectGroup<int> _numberOfClientsGroup = new ContextMenuSingleSelectGroup<int>();
/// <summary>
/// Defines a viewport scaling option.
/// </summary>
public class ViewportScaleOption
{
/// <summary>
/// Defines the viewport scale type.
/// </summary>
public enum ViewportScaleType
{
/// <summary>
/// Resolution.
/// </summary>
Resolution = 0,
/// <summary>
/// Aspect Ratio.
/// </summary>
Aspect = 1,
}
/// <summary>
/// The name.
/// </summary>
public string Label;
/// <summary>
/// The Type of scaling to do.
/// </summary>
public ViewportScaleType ScaleType;
/// <summary>
/// The width and height to scale by.
/// </summary>
public Int2 Size;
}
/// <summary>
/// The default viewport scaling options.
/// </summary>
public List<ViewportScaleOption> DefaultViewportScaleOptions = new List<ViewportScaleOption>();
/// <summary>
/// The user defined viewport scaling options.
/// </summary>
public List<ViewportScaleOption> CustomViewportScaleOptions = new List<ViewportScaleOption>();
private ContextMenuButton _menuFileSaveScenes; private ContextMenuButton _menuFileSaveScenes;
private ContextMenuButton _menuFileReloadScenes; private ContextMenuButton _menuFileReloadScenes;
@@ -456,8 +409,6 @@ namespace FlaxEditor.Modules
// Update window background // Update window background
mainWindow.BackgroundColor = Style.Current.Background; mainWindow.BackgroundColor = Style.Current.Background;
InitViewportScaleOptions();
InitSharedMenus(); InitSharedMenus();
InitMainMenu(mainWindow); InitMainMenu(mainWindow);
@@ -471,57 +422,6 @@ namespace FlaxEditor.Modules
mainWindow.PerformLayout(true); mainWindow.PerformLayout(true);
} }
private void InitViewportScaleOptions()
{
if (DefaultViewportScaleOptions.Count == 0)
{
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "Free Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(1, 1),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:9 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 9),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "16:10 Aspect",
ScaleType = ViewportScaleOption.ViewportScaleType.Aspect,
Size = new Int2(16, 10),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "1920x1080 Resolution (Full HD)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(1920, 1080),
});
DefaultViewportScaleOptions.Add(new ViewportScaleOption
{
Label = "2560x1440 Resolution (2K)",
ScaleType = ViewportScaleOption.ViewportScaleType.Resolution,
Size = new Int2(2560, 1440),
});
}
if (Editor.Instance.ProjectCache.TryGetCustomData("CustomViewportScalingOptions", out string data))
{
CustomViewportScaleOptions = JsonSerializer.Deserialize<List<ViewportScaleOption>>(data);
}
}
/// <summary>
/// Saves the custom viewport scaling options.
/// </summary>
public void SaveCustomViewportScalingOptions()
{
var customOptions = JsonSerializer.Serialize(CustomViewportScaleOptions);
Editor.Instance.ProjectCache.SetCustomData("CustomViewportScalingOptions", customOptions);
}
/// <inheritdoc /> /// <inheritdoc />
public override void OnUpdate() public override void OnUpdate()
{ {
@@ -646,7 +546,6 @@ namespace FlaxEditor.Modules
_menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync); _menuFileGenerateScriptsProjectFiles = cm.AddButton("Generate scripts project files", inputOptions.GenerateScriptsProject, Editor.ProgressReporting.GenerateScriptsProjectFiles.RunAsync);
_menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile); _menuFileRecompileScripts = cm.AddButton("Recompile scripts", inputOptions.RecompileScripts, ScriptsBuilder.Compile);
cm.AddSeparator(); cm.AddSeparator();
cm.AddButton("New project", NewProject);
cm.AddButton("Open project...", OpenProject); cm.AddButton("Open project...", OpenProject);
cm.AddButton("Reload project", ReloadProject); cm.AddButton("Reload project", ReloadProject);
cm.AddButton("Open project folder", () => FileSystem.ShowFileExplorer(Editor.Instance.GameProject.ProjectFolderPath)); cm.AddButton("Open project folder", () => FileSystem.ShowFileExplorer(Editor.Instance.GameProject.ProjectFolderPath));
@@ -677,7 +576,7 @@ namespace FlaxEditor.Modules
if (item != null) if (item != null)
Editor.ContentEditing.Open(item); Editor.ContentEditing.Open(item);
}); });
cm.AddButton("Editor Options", inputOptions.EditorOptionsWindow, () => Editor.Windows.EditorOptionsWin.Show()); cm.AddButton("Editor Options", () => Editor.Windows.EditorOptionsWin.Show());
// Scene // Scene
MenuScene = MainMenu.AddButton("Scene"); MenuScene = MainMenu.AddButton("Scene");
@@ -952,17 +851,6 @@ namespace FlaxEditor.Modules
MasterPanel.Offsets = new Margin(0, 0, ToolStrip.Bottom, StatusBar.Height); MasterPanel.Offsets = new Margin(0, 0, ToolStrip.Bottom, StatusBar.Height);
} }
private void NewProject()
{
// Ask user to create project file
if (FileSystem.ShowSaveFileDialog(Editor.Windows.MainWindow, null, "Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0", false, "Create project file", out var files))
return;
if (files != null && files.Length > 0)
{
Editor.NewProject(files[0]);
}
}
private void OpenProject() private void OpenProject()
{ {
// Ask user to select project file // Ask user to select project file
@@ -1220,267 +1108,5 @@ namespace FlaxEditor.Modules
MenuTools = null; MenuTools = null;
MenuHelp = null; MenuHelp = null;
} }
internal void CreateViewportSizingContextMenu(ContextMenu vsMenu, int defaultScaleActiveIndex, int customScaleActiveIndex, bool prefabViewport, Action<ViewportScaleOption> changeView, Action<int, int> changeActiveIndices)
{
// Add default viewport sizing options
var defaultOptions = DefaultViewportScaleOptions;
for (int i = 0; i < defaultOptions.Count; i++)
{
var viewportScale = defaultOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var button = vsMenu.AddButton(viewportScale.Label);
button.CloseMenuOnClick = false;
button.Tag = viewportScale;
// No default index is active
if (defaultScaleActiveIndex == -1)
{
button.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (defaultScaleActiveIndex == i)
{
button.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
button.Clicked += () =>
{
if (button.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (cmb == button)
{
button.Icon = Style.Current.CheckBoxTick;
var index = defaultOptions.FindIndex(x => x == v);
changeActiveIndices(index, -1); // Reset custom index because default was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
}
if (defaultOptions.Count != 0)
vsMenu.AddSeparator();
// Add custom viewport options
var customOptions = CustomViewportScaleOptions;
for (int i = 0; i < customOptions.Count; i++)
{
var viewportScale = customOptions[i];
if (prefabViewport && viewportScale.ScaleType == ViewportScaleOption.ViewportScaleType.Aspect)
continue; // Skip aspect ratio types in prefab
var childCM = vsMenu.AddChildMenu(viewportScale.Label);
childCM.CloseMenuOnClick = false;
childCM.Tag = viewportScale;
// No custom index is active
if (customScaleActiveIndex == -1)
{
childCM.Icon = SpriteHandle.Invalid;
}
// This is the active index
else if (customScaleActiveIndex == i)
{
childCM.Icon = Style.Current.CheckBoxTick;
changeView(viewportScale);
}
var applyButton = childCM.ContextMenu.AddButton("Apply");
applyButton.Tag = childCM.Tag = viewportScale;
applyButton.CloseMenuOnClick = false;
applyButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is UIModule.ViewportScaleOption v)
{
if (child == childCM)
{
childCM.Icon = Style.Current.CheckBoxTick;
var index = customOptions.FindIndex(x => x == v);
changeActiveIndices(-1, index); // Reset default index because custom was chosen
changeView(v);
}
else if (cmb.Icon != SpriteHandle.Invalid)
{
cmb.Icon = SpriteHandle.Invalid;
}
}
}
};
var deleteButton = childCM.ContextMenu.AddButton("Delete");
deleteButton.CloseMenuOnClick = false;
deleteButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
var v = (ViewportScaleOption)childCM.Tag;
if (childCM.Icon != SpriteHandle.Invalid)
{
changeActiveIndices(-1, 0);
changeView(defaultOptions[0]);
}
customOptions.Remove(v);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
}
if (customOptions.Count != 0)
vsMenu.AddSeparator();
// Add button
var add = vsMenu.AddButton("Add...");
add.CloseMenuOnClick = false;
add.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(add, new Float2(add.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var typeLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Type",
HorizontalAlignment = TextAlignment.Near,
};
typeLabel.LocalX += 10;
typeLabel.LocalY += 35;
var typeDropdown = new Dropdown
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Items = { "Aspect", "Resolution" },
SelectedItem = "Aspect",
Visible = !prefabViewport,
Width = nameTextBox.Width
};
typeDropdown.LocalY += 35;
typeDropdown.LocalX += 100;
var whLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Width & Height",
HorizontalAlignment = TextAlignment.Near,
};
whLabel.LocalX += 10;
whLabel.LocalY += 60;
var wValue = new IntValueBox(16)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
wValue.LocalY += 60;
wValue.LocalX += 100;
var hValue = new IntValueBox(9)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
hValue.LocalY += 60;
hValue.LocalX += 165;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Submit",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleOption.ViewportScaleType type);
if (prefabViewport)
type = ViewportScaleOption.ViewportScaleType.Resolution;
var combineString = type == ViewportScaleOption.ViewportScaleType.Aspect ? ":" : "x";
var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem;
var newViewportOption = new ViewportScaleOption
{
ScaleType = type,
Label = name,
Size = new Int2(wValue.Value, hValue.Value),
};
customOptions.Add(newViewportOption);
SaveCustomViewportScalingOptions();
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu, defaultScaleActiveIndex, customScaleActiveIndex, prefabViewport, changeView, changeActiveIndices);
vsMenu.PerformLayout();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
typeDropdown.SelectedItem = "Aspect";
hValue.Value = 9;
wValue.Value = 16;
popup.Hide();
};
};
}
} }
} }

View File

@@ -650,10 +650,6 @@ namespace FlaxEditor.Options
[EditorDisplay("Windows"), EditorOrder(4020)] [EditorDisplay("Windows"), EditorOrder(4020)]
public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None); public InputBinding VisualScriptDebuggerWindow = new InputBinding(KeyboardKeys.None);
[DefaultValue(typeof(InputBinding), "Control+Comma")]
[EditorDisplay("Windows"), EditorOrder(4030)]
public InputBinding EditorOptionsWindow = new InputBinding(KeyboardKeys.Comma, KeyboardKeys.Control);
#endregion #endregion
#region Node Editors #region Node Editors

View File

@@ -150,26 +150,5 @@ namespace FlaxEditor.Options
[DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")] [DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")]
[EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")] [EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")]
public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f); public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f);
/// <summary>
/// Gets or sets the minimum size used for viewport icons.
/// </summary>
[DefaultValue(7.0f), Limit(1.0f, 1000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(400)]
public float IconsMinimumSize { get; set; } = 7.0f;
/// <summary>
/// Gets or sets the maximum size used for viewport icons.
/// </summary>
[DefaultValue(30.0f), Limit(1.0f, 1000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(410)]
public float IconsMaximumSize { get; set; } = 30.0f;
/// <summary>
/// Gets or sets the distance towards the camera at which the max icon scale will be applied. Set to 0 to disable scaling the icons based on the distance to the camera.
/// </summary>
[DefaultValue(1000.0f), Limit(0.0f, 20000.0f, 5.0f)]
[EditorDisplay("Viewport Icons"), EditorOrder(410)]
public float MaxSizeDistance { get; set; } = 1000.0f;
} }
} }

View File

@@ -81,13 +81,6 @@ namespace FlaxEditor.Options
[EditorDisplay("Transform Gizmo", "Gizmo Opacity"), EditorOrder(211)] [EditorDisplay("Transform Gizmo", "Gizmo Opacity"), EditorOrder(211)]
public float TransformGizmoOpacity { get; set; } = 1f; public float TransformGizmoOpacity { get; set; } = 1f;
/// <summary>
/// Gets or set a value indicating how bright the transform gizmo is when it is disabled, for example when one of the selected actors is static in play mode. Use a value of 0 to make the gizmo fully gray. Value over 1 will result in the gizmo emitting light.
/// </summary>
[DefaultValue(0.25f), Range(0f, 5f)]
[EditorDisplay("Transform Gizmo", "Disabled Gizmo Brightness"), EditorOrder(212)]
public float TransformGizmoBrightnessDisabled { get; set; } = 0.25f;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance. /// Gets or sets a value indicating whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance.
/// </summary> /// </summary>

View File

@@ -229,20 +229,20 @@ namespace FlaxEditor.Surface
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes) protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
{ {
// Check if show additional nodes in the current surface context // Check if show additional nodes in the current surface context
if (activeCM != _cmStateMachineMenu) if (activeCM != _cmStateMachineMenu)
{ {
_nodesCache.Get(activeCM); _nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBoxes); base.OnShowPrimaryMenu(activeCM, location, startBox);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
} }
else else
{ {
base.OnShowPrimaryMenu(activeCM, location, startBoxes); base.OnShowPrimaryMenu(activeCM, location, startBox);
} }
} }

View File

@@ -1390,7 +1390,7 @@ namespace FlaxEditor.Surface.Archetypes
Elements = new[] Elements = new[]
{ {
NodeElementArchetype.Factory.Output(0, "Time", typeof(float), 0), NodeElementArchetype.Factory.Output(0, "Time", typeof(float), 0),
NodeElementArchetype.Factory.Output(1, "Scaled Time", typeof(float), 1), NodeElementArchetype.Factory.Output(1, "Unscaled Time", typeof(float), 1),
} }
}, },
new NodeArchetype new NodeArchetype

View File

@@ -101,12 +101,12 @@ namespace FlaxEditor.Surface
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes) protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
{ {
activeCM.ShowExpanded = true; activeCM.ShowExpanded = true;
_nodesCache.Get(activeCM); _nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBoxes); base.OnShowPrimaryMenu(activeCM, location, startBox);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
} }

View File

@@ -24,8 +24,8 @@ namespace FlaxEditor.Surface.ContextMenu
/// Visject context menu item clicked delegate. /// Visject context menu item clicked delegate.
/// </summary> /// </summary>
/// <param name="clickedItem">The item that was clicked</param> /// <param name="clickedItem">The item that was clicked</param>
/// <param name="selectedBoxes">The currently user-selected boxes. Can be empty/ null.</param> /// <param name="selectedBox">The currently user-selected box. Can be null.</param>
public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, List<Elements.Box> selectedBoxes); public delegate void ItemClickedDelegate(VisjectCMItem clickedItem, Elements.Box selectedBox);
/// <summary> /// <summary>
/// Visject Surface node archetype spawn ability checking delegate. /// Visject Surface node archetype spawn ability checking delegate.
@@ -53,7 +53,7 @@ namespace FlaxEditor.Surface.ContextMenu
private Panel _panel1; private Panel _panel1;
private VerticalPanel _groupsPanel; private VerticalPanel _groupsPanel;
private readonly ParameterGetterDelegate _parametersGetter; private readonly ParameterGetterDelegate _parametersGetter;
private List<Elements.Box> _selectedBoxes = new List<Elements.Box>(); private Elements.Box _selectedBox;
private NodeArchetype _parameterGetNodeArchetype; private NodeArchetype _parameterGetNodeArchetype;
private NodeArchetype _parameterSetNodeArchetype; private NodeArchetype _parameterSetNodeArchetype;
@@ -411,8 +411,7 @@ namespace FlaxEditor.Surface.ContextMenu
if (!IsLayoutLocked) if (!IsLayoutLocked)
{ {
group.UnlockChildrenRecursive(); group.UnlockChildrenRecursive();
// TODO: Improve filtering to be based on boxes with the most common things instead of first box if (_contextSensitiveSearchEnabled && _selectedBox != null)
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null)
UpdateFilters(); UpdateFilters();
else else
SortGroups(); SortGroups();
@@ -424,10 +423,9 @@ namespace FlaxEditor.Surface.ContextMenu
OnSearchFilterChanged(); OnSearchFilterChanged();
} }
} }
else if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0) else if (_contextSensitiveSearchEnabled)
{ {
// TODO: Filtering could be improved here as well group.EvaluateVisibilityWithBox(_selectedBox);
group.EvaluateVisibilityWithBox(_selectedBoxes[0]);
} }
Profiler.EndEvent(); Profiler.EndEvent();
@@ -462,8 +460,8 @@ namespace FlaxEditor.Surface.ContextMenu
Parent = group Parent = group
}; };
} }
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0) if (_contextSensitiveSearchEnabled)
group.EvaluateVisibilityWithBox(_selectedBoxes[0]); group.EvaluateVisibilityWithBox(_selectedBox);
group.SortChildren(); group.SortChildren();
if (ShowExpanded) if (ShowExpanded)
group.Open(false); group.Open(false);
@@ -476,7 +474,7 @@ namespace FlaxEditor.Surface.ContextMenu
if (!isLayoutLocked) if (!isLayoutLocked)
{ {
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count != 0 && _selectedBoxes[0] != null) if (_contextSensitiveSearchEnabled && _selectedBox != null)
UpdateFilters(); UpdateFilters();
else else
SortGroups(); SortGroups();
@@ -585,7 +583,7 @@ namespace FlaxEditor.Surface.ContextMenu
private void UpdateFilters() private void UpdateFilters()
{ {
if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBoxes[0] == null) if (string.IsNullOrEmpty(_searchBox.Text) && _selectedBox == null)
{ {
ResetView(); ResetView();
Profiler.EndEvent(); Profiler.EndEvent();
@@ -594,7 +592,7 @@ namespace FlaxEditor.Surface.ContextMenu
// Update groups // Update groups
LockChildrenRecursive(); LockChildrenRecursive();
var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 ? _selectedBoxes[0] : null; var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled ? _selectedBox : null;
for (int i = 0; i < _groups.Count; i++) for (int i = 0; i < _groups.Count; i++)
{ {
_groups[i].UpdateFilter(_searchBox.Text, contextSensitiveSelectedBox); _groups[i].UpdateFilter(_searchBox.Text, contextSensitiveSelectedBox);
@@ -642,7 +640,7 @@ namespace FlaxEditor.Surface.ContextMenu
public void OnClickItem(VisjectCMItem item) public void OnClickItem(VisjectCMItem item)
{ {
Hide(); Hide();
ItemClicked?.Invoke(item, _selectedBoxes); ItemClicked?.Invoke(item, _selectedBox);
} }
/// <summary> /// <summary>
@@ -668,12 +666,12 @@ namespace FlaxEditor.Surface.ContextMenu
for (int i = 0; i < _groups.Count; i++) for (int i = 0; i < _groups.Count; i++)
{ {
_groups[i].ResetView(); _groups[i].ResetView();
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0) if (_contextSensitiveSearchEnabled)
_groups[i].EvaluateVisibilityWithBox(_selectedBoxes[0]); _groups[i].EvaluateVisibilityWithBox(_selectedBox);
} }
UnlockChildrenRecursive(); UnlockChildrenRecursive();
if (_contextSensitiveSearchEnabled && _selectedBoxes.Count > 0 && _selectedBoxes[0] != null) if (_contextSensitiveSearchEnabled && _selectedBox != null)
UpdateFilters(); UpdateFilters();
else else
SortGroups(); SortGroups();
@@ -774,10 +772,10 @@ namespace FlaxEditor.Surface.ContextMenu
/// </summary> /// </summary>
/// <param name="parent">Parent control to attach to it.</param> /// <param name="parent">Parent control to attach to it.</param>
/// <param name="location">Popup menu origin location in parent control coordinates.</param> /// <param name="location">Popup menu origin location in parent control coordinates.</param>
/// <param name="startBoxes">The currently selected boxes that the new node will get connected to. Can be empty/ null</param> /// <param name="startBox">The currently selected box that the new node will get connected to. Can be null</param>
public void Show(Control parent, Float2 location, List<Elements.Box> startBoxes) public void Show(Control parent, Float2 location, Elements.Box startBox)
{ {
_selectedBoxes = startBoxes; _selectedBox = startBox;
base.Show(parent, location); base.Show(parent, location);
} }

View File

@@ -544,39 +544,35 @@ namespace FlaxEditor.Surface.Elements
public override void OnMouseLeave() public override void OnMouseLeave()
{ {
if (_originalTooltipText != null) if (_originalTooltipText != null)
{
TooltipText = _originalTooltipText; TooltipText = _originalTooltipText;
}
if (_isMouseDown) if (_isMouseDown)
{ {
_isMouseDown = false; _isMouseDown = false;
if (Surface.CanEdit) if (Surface.CanEdit)
{ {
if (IsOutput && Input.GetKey(KeyboardKeys.Control)) if (!IsOutput && HasSingleConnection)
{ {
List<Box> connectedBoxes = new List<Box>(Connections); var connectedBox = Connections[0];
for (int i = 0; i < connectedBoxes.Count; i++)
{
BreakConnection(connectedBoxes[i]);
Surface.ConnectingStart(connectedBoxes[i], true);
}
}
else if (!IsOutput && HasSingleConnection)
{
var otherBox = Connections[0];
if (Surface.Undo != null && Surface.Undo.Enabled) if (Surface.Undo != null && Surface.Undo.Enabled)
{ {
var action = new ConnectBoxesAction((InputBox)this, (OutputBox)otherBox, false); var action = new ConnectBoxesAction((InputBox)this, (OutputBox)connectedBox, false);
BreakConnection(otherBox); BreakConnection(connectedBox);
action.End(); action.End();
Surface.AddBatchedUndoAction(action); Surface.AddBatchedUndoAction(action);
Surface.MarkAsEdited(); Surface.MarkAsEdited();
} }
else else
BreakConnection(otherBox); {
Surface.ConnectingStart(otherBox); BreakConnection(connectedBox);
}
Surface.ConnectingStart(connectedBox);
} }
else else
{
Surface.ConnectingStart(this); Surface.ConnectingStart(this);
}
} }
} }
base.OnMouseLeave(); base.OnMouseLeave();

View File

@@ -151,8 +151,6 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
protected virtual Color FooterColor => GroupArchetype.Color; protected virtual Color FooterColor => GroupArchetype.Color;
private Float2 mouseDownMousePosition;
/// <summary> /// <summary>
/// Calculates the size of the node including header, footer, and margins. /// Calculates the size of the node including header, footer, and margins.
/// </summary> /// </summary>
@@ -919,7 +917,7 @@ namespace FlaxEditor.Surface
/// <inheritdoc /> /// <inheritdoc />
public override bool OnTestTooltipOverControl(ref Float2 location) public override bool OnTestTooltipOverControl(ref Float2 location)
{ {
return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsSelecting; return _headerRect.Contains(ref location) && ShowTooltip && !Surface.IsConnecting && !Surface.IsBoxSelecting;
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -1077,7 +1075,7 @@ namespace FlaxEditor.Surface
// Header // Header
var headerColor = style.BackgroundHighlighted; var headerColor = style.BackgroundHighlighted;
if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting) if (_headerRect.Contains(ref _mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting)
headerColor *= 1.07f; headerColor *= 1.07f;
Render2D.FillRectangle(_headerRect, headerColor); Render2D.FillRectangle(_headerRect, headerColor);
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center); Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
@@ -1085,7 +1083,7 @@ namespace FlaxEditor.Surface
// Close button // Close button
if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit) if ((Archetype.Flags & NodeFlags.NoCloseButton) == 0 && Surface.CanEdit)
{ {
bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsSelecting; bool highlightClose = _closeButtonRect.Contains(_mousePosition) && !Surface.IsConnecting && !Surface.IsBoxSelecting;
Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey); Render2D.DrawSprite(style.Cross, _closeButtonRect, highlightClose ? style.Foreground : style.ForegroundGrey);
} }
@@ -1123,7 +1121,7 @@ namespace FlaxEditor.Surface
if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) if (button == MouseButton.Left && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
return true; return true;
if (button == MouseButton.Right) if (button == MouseButton.Right)
mouseDownMousePosition = Input.Mouse.Position; return true;
return false; return false;
} }
@@ -1135,7 +1133,7 @@ namespace FlaxEditor.Surface
return true; return true;
// Close/ delete // Close/ delete
bool canDelete = !Surface.IsConnecting && !Surface.WasSelecting && !Surface.WasMovingSelection; bool canDelete = !Surface.IsConnecting && !Surface.WasBoxSelecting && !Surface.WasMovingSelection;
if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location)) if (button == MouseButton.Left && canDelete && (Archetype.Flags & NodeFlags.NoCloseButton) == 0 && _closeButtonRect.Contains(ref location))
{ {
Surface.Delete(this); Surface.Delete(this);
@@ -1145,10 +1143,6 @@ namespace FlaxEditor.Surface
// Secondary Context Menu // Secondary Context Menu
if (button == MouseButton.Right) if (button == MouseButton.Right)
{ {
float distance = Float2.Distance(mouseDownMousePosition, Input.Mouse.Position);
if (distance > 2.5f)
return true;
if (!IsSelected) if (!IsSelected)
Surface.Select(this); Surface.Select(this);
var tmp = PointToParent(ref location); var tmp = PointToParent(ref location);

View File

@@ -1,8 +1,6 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Surface.Elements;
using FlaxEngine; using FlaxEngine;
namespace FlaxEditor.Surface namespace FlaxEditor.Surface
@@ -235,15 +233,11 @@ namespace FlaxEditor.Surface
/// Begins connecting surface objects action. /// Begins connecting surface objects action.
/// </summary> /// </summary>
/// <param name="instigator">The connection instigator (eg. start box).</param> /// <param name="instigator">The connection instigator (eg. start box).</param>
/// <param name="additive">If the instigator should be added to the list of instigators.</param> public void ConnectingStart(IConnectionInstigator instigator)
public void ConnectingStart(IConnectionInstigator instigator, bool additive = false)
{ {
if (instigator != null && instigator != _connectionInstigators) if (instigator != null && instigator != _connectionInstigator)
{ {
if (!additive) _connectionInstigator = instigator;
_connectionInstigators.Clear();
_connectionInstigators.Add(instigator);
StartMouseCapture(); StartMouseCapture();
} }
} }
@@ -263,30 +257,22 @@ namespace FlaxEditor.Surface
/// <param name="end">The end object (eg. end box).</param> /// <param name="end">The end object (eg. end box).</param>
public void ConnectingEnd(IConnectionInstigator end) public void ConnectingEnd(IConnectionInstigator end)
{ {
// Ensure that there is at least one connection instigator // Ensure that there was a proper start box
if (_connectionInstigators.Count == 0) if (_connectionInstigator == null)
return; return;
List<IConnectionInstigator> instigators = new List<IConnectionInstigator>(_connectionInstigators); var start = _connectionInstigator;
for (int i = 0; i < instigators.Count; i++) _connectionInstigator = null;
// Check if boxes are different and end box is specified
if (start == end || end == null)
return;
// Connect them
if (start.CanConnectWith(end))
{ {
var start = instigators[i]; start.Connect(end);
// Check if boxes are different and end box is specified
if (start == end || end == null)
return;
// Properly handle connecting to a socket that already has a connection
if (end is Box e && !e.IsOutput && start is Box s && e.AreConnected(s))
e.BreakConnection(s);
// Connect them
if (start.CanConnectWith(end))
start.Connect(end);
} }
// Reset instigator list
_connectionInstigators.Clear();
} }
} }
} }

View File

@@ -261,10 +261,10 @@ namespace FlaxEditor.Surface
/// </summary> /// </summary>
/// <param name="activeCM">The active context menu to show.</param> /// <param name="activeCM">The active context menu to show.</param>
/// <param name="location">The display location on the surface control.</param> /// <param name="location">The display location on the surface control.</param>
/// <param name="startBoxes">The start boxes.</param> /// <param name="startBox">The start box.</param>
protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes) protected virtual void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
{ {
activeCM.Show(this, location, startBoxes); activeCM.Show(this, location, startBox);
} }
/// <summary> /// <summary>
@@ -298,10 +298,8 @@ namespace FlaxEditor.Surface
_cmStartPos = location; _cmStartPos = location;
List<Box> startBoxes = new List<Box>(_connectionInstigators.Where(c => c is Box).Cast<Box>()); // Offset added in case the user doesn't like the box and wants to quickly get rid of it by clicking
OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, _connectionInstigator as Box);
// Position offset added so the user can quickly close the menu by clicking
OnShowPrimaryMenu(_activeVisjectCM, _cmStartPos + ContextMenuOffset, startBoxes);
if (!string.IsNullOrEmpty(input)) if (!string.IsNullOrEmpty(input))
{ {
@@ -515,15 +513,17 @@ namespace FlaxEditor.Surface
private void OnPrimaryMenuVisibleChanged(Control primaryMenu) private void OnPrimaryMenuVisibleChanged(Control primaryMenu)
{ {
if (!primaryMenu.Visible) if (!primaryMenu.Visible)
_connectionInstigators.Clear(); {
_connectionInstigator = null;
}
} }
/// <summary> /// <summary>
/// Handles Visject CM item click event by spawning the selected item. /// Handles Visject CM item click event by spawning the selected item.
/// </summary> /// </summary>
/// <param name="visjectCmItem">The item.</param> /// <param name="visjectCmItem">The item.</param>
/// <param name="selectedBoxes">The selected boxes.</param> /// <param name="selectedBox">The selected box.</param>
protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, List<Box> selectedBoxes) protected virtual void OnPrimaryMenuButtonClick(VisjectCMItem visjectCmItem, Box selectedBox)
{ {
if (!CanEdit) if (!CanEdit)
return; return;
@@ -550,36 +550,34 @@ namespace FlaxEditor.Surface
// Auto select new node // Auto select new node
Select(node); Select(node);
for (int i = 0; i < selectedBoxes.Count; i++) if (selectedBox != null)
{ {
Box currentBox = selectedBoxes[i]; Box endBox = null;
if (currentBox != null) foreach (var box in node.GetBoxes().Where(box => box.IsOutput != selectedBox.IsOutput))
{ {
Box endBox = null; if (selectedBox.IsOutput)
foreach (var box in node.GetBoxes().Where(box => box.IsOutput != currentBox.IsOutput))
{ {
if (currentBox.IsOutput) if (box.CanUseType(selectedBox.CurrentType))
{ {
if (box.CanUseType(currentBox.CurrentType))
{
endBox = box;
break;
}
}
else
{
if (currentBox.CanUseType(box.CurrentType))
{
endBox = box;
break;
}
}
if (endBox == null && currentBox.CanUseType(box.CurrentType))
endBox = box; endBox = box;
break;
}
}
else
{
if (selectedBox.CanUseType(box.CurrentType))
{
endBox = box;
break;
}
}
if (endBox == null && selectedBox.CanUseType(box.CurrentType))
{
endBox = box;
} }
TryConnect(currentBox, endBox);
} }
TryConnect(selectedBox, endBox);
} }
} }
@@ -595,8 +593,13 @@ namespace FlaxEditor.Surface
} }
// If the user is patiently waiting for his box to get connected to the newly created one fulfill his wish! // If the user is patiently waiting for his box to get connected to the newly created one fulfill his wish!
_connectionInstigator = startBox;
if (!IsConnecting) if (!IsConnecting)
{
ConnectingStart(startBox); ConnectingStart(startBox);
}
ConnectingEnd(endBox); ConnectingEnd(endBox);
// Smart-Select next box // Smart-Select next box

View File

@@ -1,6 +1,5 @@
// Copyright (c) Wojciech Figat. All rights reserved. // Copyright (c) Wojciech Figat. All rights reserved.
using System.Collections.Generic;
using FlaxEditor.Surface.Elements; using FlaxEditor.Surface.Elements;
using FlaxEngine; using FlaxEngine;
@@ -127,45 +126,40 @@ namespace FlaxEditor.Surface
/// <remarks>Called only when user is connecting nodes.</remarks> /// <remarks>Called only when user is connecting nodes.</remarks>
protected virtual void DrawConnectingLine() protected virtual void DrawConnectingLine()
{ {
// Get start position
var startPos = _connectionInstigator.ConnectionOrigin;
// Check if mouse is over any of box
var cmVisible = _activeVisjectCM != null && _activeVisjectCM.Visible; var cmVisible = _activeVisjectCM != null && _activeVisjectCM.Visible;
var endPos = cmVisible ? _rootControl.PointFromParent(ref _cmStartPos) : _rootControl.PointFromParent(ref _mousePos); var endPos = cmVisible ? _rootControl.PointFromParent(ref _cmStartPos) : _rootControl.PointFromParent(ref _mousePos);
Color lineColor = Style.Colors.Connecting; Color lineColor = Style.Colors.Connecting;
if (_lastInstigatorUnderMouse != null && !cmVisible)
List<IConnectionInstigator> instigators = new List<IConnectionInstigator>(_connectionInstigators);
for (int i = 0; i < instigators.Count; i++)
{ {
IConnectionInstigator currentInstigator = instigators[i]; // Check if can connect objects
Float2 currentStartPosition = currentInstigator.ConnectionOrigin; bool canConnect = _connectionInstigator.CanConnectWith(_lastInstigatorUnderMouse);
lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid;
endPos = _lastInstigatorUnderMouse.ConnectionOrigin;
}
// Check if mouse is over any box Float2 actualStartPos = startPos;
if (_lastInstigatorUnderMouse != null && !cmVisible) Float2 actualEndPos = endPos;
{
// Check if can connect objects
bool canConnect = currentInstigator.CanConnectWith(_lastInstigatorUnderMouse);
lineColor = canConnect ? Style.Colors.ConnectingValid : Style.Colors.ConnectingInvalid;
endPos = _lastInstigatorUnderMouse.ConnectionOrigin;
}
Float2 actualStartPos = currentStartPosition; if (_connectionInstigator is Archetypes.Tools.RerouteNode)
Float2 actualEndPos = endPos; {
if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true })
if (currentInstigator is Archetypes.Tools.RerouteNode)
{
if (endPos.X < currentStartPosition.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true })
{
actualStartPos = endPos;
actualEndPos = currentStartPosition;
}
}
else if (currentInstigator is Box { IsOutput: false })
{ {
actualStartPos = endPos; actualStartPos = endPos;
actualEndPos = currentStartPosition; actualEndPos = startPos;
} }
// Draw connection
currentInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor);
} }
else if (_connectionInstigator is Box { IsOutput: false })
{
actualStartPos = endPos;
actualEndPos = startPos;
}
// Draw connection
_connectionInstigator.DrawConnectingLine(ref actualStartPos, ref actualEndPos, ref lineColor);
} }
/// <summary> /// <summary>
@@ -232,10 +226,10 @@ namespace FlaxEditor.Surface
_rootControl.DrawComments(); _rootControl.DrawComments();
// Reset input flags here because this is the closest to Update we have // Reset input flags here because this is the closest to Update we have
WasSelecting = IsSelecting; WasBoxSelecting = IsBoxSelecting;
WasMovingSelection = IsMovingSelection; WasMovingSelection = IsMovingSelection;
if (IsSelecting) if (IsBoxSelecting)
{ {
DrawSelection(); DrawSelection();
} }

View File

@@ -176,10 +176,10 @@ namespace FlaxEditor.Surface
if (connectedNodes.Count == 0) if (connectedNodes.Count == 0)
return; return;
for (int i = 0; i < connectedNodes.Count; i++) for (int i = 0; i < connectedNodes.Count - 1; i++)
{ {
SurfaceNode nodeA = connectedNodes[i]; SurfaceNode nodeA = connectedNodes[i];
List<Box> connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.HasAnyConnection).ToList(); List<Box> connectedOutputBoxes = nodeA.GetBoxes().Where(b => b.IsOutput && b.HasAnyConnection).ToList();
for (int j = 0; j < connectedOutputBoxes.Count; j++) for (int j = 0; j < connectedOutputBoxes.Count; j++)
{ {

View File

@@ -292,7 +292,7 @@ namespace FlaxEditor.Surface
if (_leftMouseDown) if (_leftMouseDown)
{ {
// Connecting // Connecting
if (_connectionInstigators.Count > 0) if (_connectionInstigator != null)
{ {
} }
// Moving // Moving
@@ -462,7 +462,7 @@ namespace FlaxEditor.Surface
public override bool OnMouseDown(Float2 location, MouseButton button) public override bool OnMouseDown(Float2 location, MouseButton button)
{ {
// Check if user is connecting boxes // Check if user is connecting boxes
if (_connectionInstigators.Count > 0) if (_connectionInstigator != null)
return true; return true;
// Base // Base
@@ -608,7 +608,7 @@ namespace FlaxEditor.Surface
_movingNodesDelta = Float2.Zero; _movingNodesDelta = Float2.Zero;
} }
// Connecting // Connecting
else if (_connectionInstigators.Count > 0) else if (_connectionInstigator != null)
{ {
} }
// Selecting // Selecting
@@ -680,7 +680,7 @@ namespace FlaxEditor.Surface
ShowPrimaryMenu(_cmStartPos); ShowPrimaryMenu(_cmStartPos);
} }
// Letting go of a connection or right clicking while creating a connection // Letting go of a connection or right clicking while creating a connection
else if (!_isMovingSelection && _connectionInstigators.Count > 0 && !IsPrimaryMenuOpened) else if (!_isMovingSelection && _connectionInstigator != null && !IsPrimaryMenuOpened)
{ {
_cmStartPos = location; _cmStartPos = location;
Cursor = CursorType.Default; Cursor = CursorType.Default;

View File

@@ -33,7 +33,7 @@ namespace FlaxEditor.Surface
Enabled = false; Enabled = false;
// Clean data // Clean data
_connectionInstigators.Clear(); _connectionInstigator = null;
_lastInstigatorUnderMouse = null; _lastInstigatorUnderMouse = null;
var failed = RootContext.Load(); var failed = RootContext.Load();

View File

@@ -121,7 +121,7 @@ namespace FlaxEditor.Surface
/// <summary> /// <summary>
/// The connection start. /// The connection start.
/// </summary> /// </summary>
protected List<IConnectionInstigator> _connectionInstigators = new List<IConnectionInstigator>(); protected IConnectionInstigator _connectionInstigator;
/// <summary> /// <summary>
/// The last connection instigator under mouse. /// The last connection instigator under mouse.
@@ -232,19 +232,19 @@ namespace FlaxEditor.Surface
} }
/// <summary> /// <summary>
/// Gets a value indicating whether user is selecting nodes. /// Gets a value indicating whether user is box selecting nodes.
/// </summary> /// </summary>
public bool IsSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigators.Count == 0; public bool IsBoxSelecting => _leftMouseDown && !_isMovingSelection && _connectionInstigator == null;
/// <summary> /// <summary>
/// Gets a value indicating whether user was previously selecting nodes. /// Gets a value indicating whether user was previously box selecting nodes.
/// </summary> /// </summary>
public bool WasSelecting { get; private set; } public bool WasBoxSelecting { get; private set; }
/// <summary> /// <summary>
/// Gets a value indicating whether user is moving selected nodes. /// Gets a value indicating whether user is moving selected nodes.
/// </summary> /// </summary>
public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigators.Count == 0; public bool IsMovingSelection => _leftMouseDown && _isMovingSelection && _connectionInstigator == null;
/// <summary> /// <summary>
/// Gets a value indicating whether user was previously moving selected nodes. /// Gets a value indicating whether user was previously moving selected nodes.
@@ -254,7 +254,7 @@ namespace FlaxEditor.Surface
/// <summary> /// <summary>
/// Gets a value indicating whether user is connecting nodes. /// Gets a value indicating whether user is connecting nodes.
/// </summary> /// </summary>
public bool IsConnecting => _connectionInstigators.Count > 0; public bool IsConnecting => _connectionInstigator != null;
/// <summary> /// <summary>
/// Gets a value indicating whether the left mouse button is down. /// Gets a value indicating whether the left mouse button is down.

View File

@@ -212,7 +212,7 @@ namespace FlaxEditor.Surface
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, List<Box> startBoxes) protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
{ {
// Update nodes for method overrides // Update nodes for method overrides
Profiler.BeginEvent("Overrides"); Profiler.BeginEvent("Overrides");
@@ -268,7 +268,7 @@ namespace FlaxEditor.Surface
// Update nodes for invoke methods (async) // Update nodes for invoke methods (async)
_nodesCache.Get(activeCM); _nodesCache.Get(activeCM);
base.OnShowPrimaryMenu(activeCM, location, startBoxes); base.OnShowPrimaryMenu(activeCM, location, startBox);
activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged; activeCM.VisibleChanged += OnActiveContextMenuVisibleChanged;
} }

View File

@@ -149,13 +149,13 @@ bool GetTextureDataForSampling(Texture* texture, TextureDataResult& data, bool h
bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches, Texture* heightmap, float heightmapScale, Texture* splatmap1, Texture* splatmap2) bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches, Texture* heightmap, float heightmapScale, Texture* splatmap1, Texture* splatmap2)
{ {
PROFILE_CPU_NAMED("Terrain.GenerateTerrain");
CHECK_RETURN(terrain && terrain->GetChunkSize() != 0, true); CHECK_RETURN(terrain && terrain->GetChunkSize() != 0, true);
if (numberOfPatches.X < 1 || numberOfPatches.Y < 1) if (numberOfPatches.X < 1 || numberOfPatches.Y < 1)
{ {
LOG(Warning, "Cannot setup terrain with no patches."); LOG(Warning, "Cannot setup terain with no patches.");
return false; return false;
} }
PROFILE_CPU_NAMED("Terrain.GenerateTerrain");
// Wait for assets to be loaded // Wait for assets to be loaded
if (heightmap && heightmap->WaitForLoaded()) if (heightmap && heightmap->WaitForLoaded())
@@ -178,9 +178,7 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
terrain->AddPatches(numberOfPatches); terrain->AddPatches(numberOfPatches);
// Prepare data // Prepare data
const int32 heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1; const auto heightmapSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
const float heightmapSizeInv = 1.0f / (float)(heightmapSize - 1);
const Float2 uvPerPatch = Float2::One / Float2(numberOfPatches);
Array<float> heightmapData; Array<float> heightmapData;
heightmapData.Resize(heightmapSize * heightmapSize); heightmapData.Resize(heightmapSize * heightmapSize);
@@ -194,17 +192,19 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
const auto sampler = PixelFormatSampler::Get(dataHeightmap.Format); const auto sampler = PixelFormatSampler::Get(dataHeightmap.Format);
// Initialize with sub-range of the input heightmap // Initialize with sub-range of the input heightmap
const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches);
const float heightmapSizeInv = 1.0f / (heightmapSize - 1);
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{ {
auto patch = terrain->GetPatch(patchIndex); auto patch = terrain->GetPatch(patchIndex);
const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch; const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
// Sample heightmap pixels with interpolation to get actual heightmap vertices locations // Sample heightmap pixels with interpolation to get actual heightmap vertices locations
for (int32 z = 0; z < heightmapSize; z++) for (int32 z = 0; z < heightmapSize; z++)
{ {
for (int32 x = 0; x < heightmapSize; x++) for (int32 x = 0; x < heightmapSize; x++)
{ {
const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Color color = sampler->SampleLinear(dataHeightmap.Mip0DataPtr->Get(), uv, dataHeightmap.Mip0Size, dataHeightmap.RowPitch); const Color color = sampler->SampleLinear(dataHeightmap.Mip0DataPtr->Get(), uv, dataHeightmap.Mip0Size, dataHeightmap.RowPitch);
heightmapData[z * heightmapSize + x] = color.R * heightmapScale; heightmapData[z * heightmapSize + x] = color.R * heightmapScale;
} }
@@ -230,30 +230,37 @@ bool TerrainTools::GenerateTerrain(Terrain* terrain, const Int2& numberOfPatches
Texture* splatmaps[2] = { splatmap1, splatmap2 }; Texture* splatmaps[2] = { splatmap1, splatmap2 };
Array<Color32> splatmapData; Array<Color32> splatmapData;
TextureDataResult data1; TextureDataResult data1;
const Vector2 uvPerPatch = Vector2::One / Vector2(numberOfPatches);
const float heightmapSizeInv = 1.0f / (heightmapSize - 1);
for (int32 index = 0; index < ARRAY_COUNT(splatmaps); index++) for (int32 index = 0; index < ARRAY_COUNT(splatmaps); index++)
{ {
const auto splatmap = splatmaps[index]; const auto splatmap = splatmaps[index];
if (!splatmap) if (!splatmap)
continue; continue;
// Prepare data
if (splatmapData.IsEmpty())
splatmapData.Resize(heightmapSize * heightmapSize);
// Get splatmap data // Get splatmap data
if (GetTextureDataForSampling(splatmap, data1)) if (GetTextureDataForSampling(splatmap, data1))
return true; return true;
const auto sampler = PixelFormatSampler::Get(data1.Format); const auto sampler = PixelFormatSampler::Get(data1.Format);
// Modify heightmap splatmaps with sub-range of the input splatmaps // Modify heightmap splatmaps with sub-range of the input splatmaps
splatmapData.Resize(heightmapSize * heightmapSize);
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{ {
auto patch = terrain->GetPatch(patchIndex); auto patch = terrain->GetPatch(patchIndex);
const Float2 uvStart = Float2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
const Vector2 uvStart = Vector2((float)patch->GetX(), (float)patch->GetZ()) * uvPerPatch;
// Sample splatmap pixels with interpolation to get actual splatmap values // Sample splatmap pixels with interpolation to get actual splatmap values
for (int32 z = 0; z < heightmapSize; z++) for (int32 z = 0; z < heightmapSize; z++)
{ {
for (int32 x = 0; x < heightmapSize; x++) for (int32 x = 0; x < heightmapSize; x++)
{ {
const Float2 uv = uvStart + Float2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch; const Vector2 uv = uvStart + Vector2(x * heightmapSizeInv, z * heightmapSizeInv) * uvPerPatch;
const Color color = sampler->SampleLinear(data1.Mip0DataPtr->Get(), uv, data1.Mip0Size, data1.RowPitch); const Color color = sampler->SampleLinear(data1.Mip0DataPtr->Get(), uv, data1.Mip0Size, data1.RowPitch);
Color32 layers; Color32 layers;
@@ -367,38 +374,63 @@ Color32* TerrainTools::GetSplatMapData(Terrain* terrain, const Int2& patchCoord,
bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder) bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
{ {
PROFILE_CPU_NAMED("Terrain.ExportTerrain");
CHECK_RETURN(terrain && terrain->GetPatchesCount() != 0, true); CHECK_RETURN(terrain && terrain->GetPatchesCount() != 0, true);
const auto firstPatch = terrain->GetPatch(0);
// Calculate texture size
const int32 patchEdgeVertexCount = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
const int32 patchVertexCount = patchEdgeVertexCount * patchEdgeVertexCount;
// Find size of heightmap in patches // Find size of heightmap in patches
const auto firstPatch = terrain->GetPatch(0);
Int2 start(firstPatch->GetX(), firstPatch->GetZ()); Int2 start(firstPatch->GetX(), firstPatch->GetZ());
Int2 end(start); Int2 end(start);
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) for (int32 i = 0; i < terrain->GetPatchesCount(); i++)
{ {
const auto patch = terrain->GetPatch(patchIndex); const int32 x = terrain->GetPatch(i)->GetX();
const Int2 pos(patch->GetX(), patch->GetZ()); const int32 y = terrain->GetPatch(i)->GetZ();
start = Int2::Min(start, pos);
end = Int2::Max(end, pos); if (x < start.X)
start.X = x;
if (y < start.Y)
start.Y = y;
if (x > end.X)
end.X = x;
if (y > end.Y)
end.Y = y;
} }
const Int2 size = (end + 1) - start; const Int2 size = (end + 1) - start;
// Allocate heightmap for a whole terrain (NumberOfPatches * 4x4 * ChunkSize + 1) // Allocate - with space for non-existent patches
const Int2 heightmapSize = size * Terrain::ChunksCountEdge * terrain->GetChunkSize() + 1;
Array<float> heightmap; Array<float> heightmap;
heightmap.Resize(heightmapSize.X * heightmapSize.Y); heightmap.Resize(patchVertexCount * size.X * size.Y);
// Set to any element, where: min < elem < max
heightmap.SetAll(firstPatch->GetHeightmapData()[0]); heightmap.SetAll(firstPatch->GetHeightmapData()[0]);
// Fill heightmap with data from all patches const int32 heightmapWidth = patchEdgeVertexCount * size.X;
const int32 rowSize = terrain->GetChunkSize() * Terrain::ChunksCountEdge + 1;
// Fill heightmap with data
for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++) for (int32 patchIndex = 0; patchIndex < terrain->GetPatchesCount(); patchIndex++)
{ {
// Pick a patch
const auto patch = terrain->GetPatch(patchIndex); const auto patch = terrain->GetPatch(patchIndex);
const Int2 pos(patch->GetX() - start.X, patch->GetZ() - start.Y); const float* data = patch->GetHeightmapData();
const float* src = patch->GetHeightmapData();
float* dst = heightmap.Get() + pos.X * (rowSize - 1) + pos.Y * heightmapSize.X * (rowSize - 1); // Beginning of patch
for (int32 row = 0; row < rowSize; row++) int32 dstIndex = (patch->GetX() - start.X) * patchEdgeVertexCount +
Platform::MemoryCopy(dst + row * heightmapSize.X, src + row * rowSize, rowSize * sizeof(float)); (patch->GetZ() - start.Y) * size.Y * patchVertexCount;
// Iterate over lines in patch
for (int32 z = 0; z < patchEdgeVertexCount; z++)
{
// Iterate over vertices in line
for (int32 x = 0; x < patchEdgeVertexCount; x++)
{
heightmap[dstIndex + x] = data[z * patchEdgeVertexCount + x];
}
dstIndex += heightmapWidth;
}
} }
// Interpolate to 16-bit int // Interpolate to 16-bit int
@@ -406,42 +438,44 @@ bool TerrainTools::ExportTerrain(Terrain* terrain, String outputFolder)
maxHeight = minHeight = heightmap[0]; maxHeight = minHeight = heightmap[0];
for (int32 i = 1; i < heightmap.Count(); i++) for (int32 i = 1; i < heightmap.Count(); i++)
{ {
float h = heightmap.Get()[i]; float h = heightmap[i];
if (maxHeight < h) if (maxHeight < h)
maxHeight = h; maxHeight = h;
else if (minHeight > h) else if (minHeight > h)
minHeight = h; minHeight = h;
} }
const float alpha = MAX_uint16 / (maxHeight - minHeight);
const float maxValue = 65535.0f;
const float alpha = maxValue / (maxHeight - minHeight);
// Storage for pixel data // Storage for pixel data
Array<uint16> byteHeightmap; Array<uint16> byteHeightmap(heightmap.Capacity());
byteHeightmap.Resize(heightmap.Count());
for (int32 i = 0; i < heightmap.Count(); i++) for (auto& elem : heightmap)
{ {
float height = heightmap.Get()[i]; byteHeightmap.Add(static_cast<uint16>(alpha * (elem - minHeight)));
byteHeightmap.Get()[i] = static_cast<uint16>(alpha * (height - minHeight));
} }
// Create texture // Create texture
TextureData textureData; TextureData textureData;
textureData.Width = heightmapSize.X; textureData.Height = textureData.Width = heightmapWidth;
textureData.Height = heightmapSize.Y;
textureData.Depth = 1; textureData.Depth = 1;
textureData.Format = PixelFormat::R16_UNorm; textureData.Format = PixelFormat::R16_UNorm;
textureData.Items.Resize(1); textureData.Items.Resize(1);
textureData.Items[0].Mips.Resize(1); textureData.Items[0].Mips.Resize(1);
// Fill mip data
TextureMipData* srcMip = textureData.GetData(0, 0); TextureMipData* srcMip = textureData.GetData(0, 0);
srcMip->Data.Link(byteHeightmap.Get()); srcMip->Data.Link(byteHeightmap.Get());
srcMip->Lines = textureData.Height; srcMip->Lines = textureData.Height;
srcMip->RowPitch = textureData.Width * sizeof(uint16); srcMip->RowPitch = textureData.Width * 2; // 2 bytes per pixel for format R16
srcMip->DepthPitch = srcMip->Lines * srcMip->RowPitch; srcMip->DepthPitch = srcMip->Lines * srcMip->RowPitch;
// Find next non-existing file heightmap file // Find next non-existing file heightmap file
FileSystem::NormalizePath(outputFolder); FileSystem::NormalizePath(outputFolder);
const String baseFileName(TEXT("heightmap")); const String baseFileName(TEXT("heightmap"));
String outputPath; String outputPath;
for (int32 i = 0; i < 100; i++) for (int32 i = 0; i < MAX_int32; i++)
{ {
outputPath = outputFolder / baseFileName + StringUtils::ToString(i) + TEXT(".png"); outputPath = outputFolder / baseFileName + StringUtils::ToString(i) + TEXT(".png");
if (!FileSystem::FileExists(outputPath)) if (!FileSystem::FileExists(outputPath))

View File

@@ -212,10 +212,6 @@ namespace FlaxEditor.Utilities
if (value is FlaxEngine.Object) if (value is FlaxEngine.Object)
return value; return value;
// For custom types use interface
if (value is ICloneable clonable)
return clonable.Clone();
// For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor // For objects (eg. arrays) we need to clone them to prevent editing default/reference value within editor
if (value != null && (!value.GetType().IsValueType || !value.GetType().IsClass)) if (value != null && (!value.GetType().IsValueType || !value.GetType().IsClass))
{ {
@@ -552,26 +548,6 @@ namespace FlaxEditor.Utilities
return arr; return arr;
} }
internal static void StructureToByteArray(object value, int valueSize, IntPtr tempBuffer, byte[] dataBuffer)
{
var valueType = value.GetType();
if (valueType.IsEnum)
{
var ptr = FlaxEngine.Interop.NativeInterop.ValueTypeUnboxer.GetPointer(value, valueType);
FlaxEngine.Utils.MemoryCopy(tempBuffer, ptr, (ulong)valueSize);
}
else
Marshal.StructureToPtr(value, tempBuffer, true);
Marshal.Copy(tempBuffer, dataBuffer, 0, valueSize);
}
internal static object ByteArrayToStructure(IntPtr valuePtr, Type valueType, int valueSize)
{
if (valueType.IsEnum)
return FlaxEngine.Interop.NativeInterop.MarshalToManaged(valuePtr, valueType);
return Marshal.PtrToStructure(valuePtr, valueType);
}
internal static unsafe string ReadStr(this BinaryReader stream, int check) internal static unsafe string ReadStr(this BinaryReader stream, int check)
{ {
int length = stream.ReadInt32(); int length = stream.ReadInt32();

View File

@@ -66,14 +66,13 @@ public:
ViewportIconsRendererService ViewportIconsRendererServiceInstance; ViewportIconsRendererService ViewportIconsRendererServiceInstance;
float ViewportIconsRenderer::Scale = 1.0f; float ViewportIconsRenderer::Scale = 1.0f;
Real ViewportIconsRenderer::MinSize = 7.0f;
Real ViewportIconsRenderer::MaxSize = 30.0f;
Real ViewportIconsRenderer::MaxSizeDistance = 1000.0f;
void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds) void ViewportIconsRenderer::GetBounds(const Vector3& position, const Vector3& viewPosition, BoundingSphere& bounds)
{ {
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / MaxSizeDistance); constexpr Real minSize = 7.0;
Real radius = MinSize + Math::Min<Real>(scale, 1.0f) * (MaxSize - MinSize); constexpr Real maxSize = 30.0;
Real scale = Math::Square(Vector3::Distance(position, viewPosition) / 1000.0f);
Real radius = minSize + Math::Min<Real>(scale, 1.0f) * (maxSize - minSize);
bounds = BoundingSphere(position, radius * Scale); bounds = BoundingSphere(position, radius * Scale);
} }
@@ -89,7 +88,6 @@ void ViewportIconsRenderer::DrawIcons(RenderContext& renderContext, Actor* actor
draw.Flags = StaticFlags::Transform; draw.Flags = StaticFlags::Transform;
draw.DrawModes = DrawPass::Forward; draw.DrawModes = DrawPass::Forward;
draw.PerInstanceRandom = 0; draw.PerInstanceRandom = 0;
draw.StencilValue = 0;
draw.LODBias = 0; draw.LODBias = 0;
draw.ForcedLOD = -1; draw.ForcedLOD = -1;
draw.SortOrder = 0; draw.SortOrder = 0;

View File

@@ -22,21 +22,6 @@ public:
/// </summary> /// </summary>
API_FIELD() static float Scale; API_FIELD() static float Scale;
/// <summary>
/// The minimum size of the icons.
/// </summary>
API_FIELD() static Real MinSize;
/// <summary>
/// The maximum size of the icons.
/// </summary>
API_FIELD() static Real MaxSize;
/// <summary>
/// The distance to the camera at which the icons will be drawn at their maximum size.
/// </summary>
API_FIELD() static Real MaxSizeDistance;
/// <summary> /// <summary>
/// Draws the icons for the actors in the given scene (or actor tree). /// Draws the icons for the actors in the given scene (or actor tree).
/// </summary> /// </summary>

View File

@@ -541,7 +541,7 @@ namespace FlaxEditor.Viewport
// Setup options // Setup options
{ {
_editor.Options.OptionsChanged += OnEditorOptionsChanged; Editor.Instance.Options.OptionsChanged += OnEditorOptionsChanged;
SetupViewportOptions(); SetupViewportOptions();
} }
@@ -587,7 +587,7 @@ namespace FlaxEditor.Viewport
// Camera Settings Menu // Camera Settings Menu
var cameraCM = new ContextMenu(); var cameraCM = new ContextMenu();
_cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), _editor.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth) _cameraButton = new ViewportWidgetButton(string.Format(MovementSpeedTextFormat, _movementSpeed), Editor.Instance.Icons.Camera64, cameraCM, false, cameraSpeedTextWidth)
{ {
Tag = this, Tag = this,
TooltipText = "Camera Settings", TooltipText = "Camera Settings",
@@ -596,7 +596,7 @@ namespace FlaxEditor.Viewport
_cameraWidget.Parent = this; _cameraWidget.Parent = this;
// Orthographic/Perspective Mode Widget // Orthographic/Perspective Mode Widget
_orthographicModeButton = new ViewportWidgetButton(string.Empty, _editor.Icons.CamSpeed32, null, true) _orthographicModeButton = new ViewportWidgetButton(string.Empty, Editor.Instance.Icons.CamSpeed32, null, true)
{ {
Checked = !_isOrtho, Checked = !_isOrtho,
TooltipText = "Toggle Orthographic/Perspective Mode", TooltipText = "Toggle Orthographic/Perspective Mode",
@@ -869,8 +869,8 @@ namespace FlaxEditor.Viewport
{ {
} }
}); });
viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = _editor.Icons.Rotate32; viewLayers.AddButton("Reset layers", () => Task.ViewLayersMask = LayersMask.Default).Icon = Editor.Instance.Icons.Rotate32;
viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0)); viewLayers.AddButton("Disable layers", () => Task.ViewLayersMask = new LayersMask(0)).Icon = Editor.Instance.Icons.Rotate32;
viewLayers.AddSeparator(); viewLayers.AddSeparator();
var layers = LayersAndTagsSettings.GetCurrentLayers(); var layers = LayersAndTagsSettings.GetCurrentLayers();
if (layers != null && layers.Length > 0) if (layers != null && layers.Length > 0)
@@ -910,8 +910,8 @@ namespace FlaxEditor.Viewport
{ {
} }
}); });
viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = _editor.Icons.Rotate32; viewFlags.AddButton("Reset flags", () => Task.ViewFlags = ViewFlags.DefaultEditor).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None); viewFlags.AddButton("Disable flags", () => Task.ViewFlags = ViewFlags.None).Icon = Editor.Instance.Icons.Rotate32;
viewFlags.AddSeparator(); viewFlags.AddSeparator();
for (int i = 0; i < ViewFlagsValues.Length; i++) for (int i = 0; i < ViewFlagsValues.Length; i++)
{ {
@@ -1091,7 +1091,7 @@ namespace FlaxEditor.Viewport
/// </summary> /// </summary>
private void SetupViewportOptions() private void SetupViewportOptions()
{ {
var options = _editor.Options.Options; var options = Editor.Instance.Options.Options;
_minMovementSpeed = options.Viewport.MinMovementSpeed; _minMovementSpeed = options.Viewport.MinMovementSpeed;
MovementSpeed = options.Viewport.MovementSpeed; MovementSpeed = options.Viewport.MovementSpeed;
_maxMovementSpeed = options.Viewport.MaxMovementSpeed; _maxMovementSpeed = options.Viewport.MaxMovementSpeed;
@@ -1298,11 +1298,6 @@ namespace FlaxEditor.Viewport
_mouseSensitivity = options.Viewport.MouseSensitivity; _mouseSensitivity = options.Viewport.MouseSensitivity;
_maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps; _maxSpeedSteps = options.Viewport.TotalCameraSpeedSteps;
_cameraEasingDegree = options.Viewport.CameraEasingDegree; _cameraEasingDegree = options.Viewport.CameraEasingDegree;
ViewportIconsRenderer.MinSize = options.Viewport.IconsMinimumSize;
ViewportIconsRenderer.MaxSize = options.Viewport.IconsMaximumSize;
ViewportIconsRenderer.MaxSizeDistance = options.Viewport.MaxSizeDistance;
OnCameraMovementProgressChanged(); OnCameraMovementProgressChanged();
} }
@@ -1716,7 +1711,7 @@ namespace FlaxEditor.Viewport
// Check if update mouse // Check if update mouse
var size = Size; var size = Size;
var options = _editor.Options.Options; var options = Editor.Instance.Options.Options;
if (_isControllingMouse) if (_isControllingMouse)
{ {
var rmbWheel = false; var rmbWheel = false;
@@ -1957,7 +1952,7 @@ namespace FlaxEditor.Viewport
return true; return true;
// Custom input events // Custom input events
return InputActions.Process(_editor, this, key); return InputActions.Process(Editor.Instance, this, key);
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -1974,7 +1969,7 @@ namespace FlaxEditor.Viewport
base.Draw(); base.Draw();
// Add overlay during debugger breakpoint hang // Add overlay during debugger breakpoint hang
if (_editor.Simulation.IsDuringBreakpointHang) if (Editor.Instance.Simulation.IsDuringBreakpointHang)
{ {
var bounds = new Rectangle(Float2.Zero, Size); var bounds = new Rectangle(Float2.Zero, Size);
Render2D.FillRectangle(bounds, new Color(0.0f, 0.0f, 0.0f, 0.2f)); Render2D.FillRectangle(bounds, new Color(0.0f, 0.0f, 0.0f, 0.2f));
@@ -1999,7 +1994,7 @@ namespace FlaxEditor.Viewport
/// <inheritdoc /> /// <inheritdoc />
public override void OnDestroy() public override void OnDestroy()
{ {
_editor.Options.OptionsChanged -= OnEditorOptionsChanged; Editor.Instance.Options.OptionsChanged -= OnEditorOptionsChanged;
base.OnDestroy(); base.OnDestroy();
} }

View File

@@ -6,8 +6,6 @@ using System.Linq;
using FlaxEditor.Content; using FlaxEditor.Content;
using FlaxEditor.Gizmo; using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input;
using FlaxEditor.Modules;
using FlaxEditor.SceneGraph; using FlaxEditor.SceneGraph;
using FlaxEditor.Scripting; using FlaxEditor.Scripting;
using FlaxEditor.Viewport.Cameras; using FlaxEditor.Viewport.Cameras;
@@ -15,7 +13,6 @@ using FlaxEditor.Viewport.Previews;
using FlaxEditor.Windows.Assets; using FlaxEditor.Windows.Assets;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
using FlaxEngine.Json;
using Utils = FlaxEditor.Utilities.Utils; using Utils = FlaxEditor.Utilities.Utils;
namespace FlaxEditor.Viewport namespace FlaxEditor.Viewport
@@ -73,11 +70,8 @@ namespace FlaxEditor.Viewport
private PrefabUIEditorRoot _uiRoot; private PrefabUIEditorRoot _uiRoot;
private bool _showUI = false; private bool _showUI = false;
private int _defaultScaleActiveIndex = 0;
private int _customScaleActiveIndex = -1;
private ContextMenuButton _uiModeButton; private ContextMenuButton _uiModeButton;
private ContextMenuChildMenu _uiViewOptions;
/// <summary> /// <summary>
/// Event fired when the UI Mode is toggled. /// Event fired when the UI Mode is toggled.
@@ -143,8 +137,6 @@ namespace FlaxEditor.Viewport
UseAutomaticTaskManagement = defaultFeatures; UseAutomaticTaskManagement = defaultFeatures;
ShowDefaultSceneActors = defaultFeatures; ShowDefaultSceneActors = defaultFeatures;
TintColor = defaultFeatures ? Color.White : Color.Transparent; TintColor = defaultFeatures ? Color.White : Color.Transparent;
if (_uiViewOptions != null)
_uiViewOptions.Visible = _showUI;
UIModeToggled?.Invoke(_showUI); UIModeToggled?.Invoke(_showUI);
} }
} }
@@ -218,7 +210,7 @@ namespace FlaxEditor.Viewport
_uiParentLink = _uiRoot.UIRoot; _uiParentLink = _uiRoot.UIRoot;
// UI mode buton // UI mode buton
_uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", button => ShowUI = button.Checked); _uiModeButton = ViewWidgetShowMenu.AddButton("UI Mode", (button) => ShowUI = button.Checked);
_uiModeButton.AutoCheck = true; _uiModeButton.AutoCheck = true;
_uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI; _uiModeButton.VisibleChanged += control => (control as ContextMenuButton).Checked = ShowUI;
@@ -230,91 +222,6 @@ namespace FlaxEditor.Viewport
SetUpdate(ref _update, OnUpdate); SetUpdate(ref _update, OnUpdate);
} }
/// <summary>
/// Creates the view scaling options. Needs to be called after a Prefab is valid and loaded.
/// </summary>
public void CreateViewScalingOptions()
{
if (_uiViewOptions != null)
return;
_uiViewOptions = ViewWidgetButtonMenu.AddChildMenu("UI View Scaling");
_uiViewOptions.Visible = _showUI;
LoadCustomUIScalingOption();
Editor.Instance.UI.CreateViewportSizingContextMenu(_uiViewOptions.ContextMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, true, ChangeUIView, (a, b) =>
{
_defaultScaleActiveIndex = a;
_customScaleActiveIndex = b;
});
}
private void ChangeUIView(UIModule.ViewportScaleOption uiViewScaleOption)
{
_uiRoot.SetViewSize((Float2)uiViewScaleOption.Size);
}
/// <summary>
/// Saves the active ui scaling option.
/// </summary>
public void SaveActiveUIScalingOption()
{
if (!Prefab)
return;
var id = Prefab.ID;
var defaultKey = $"{id}:DefaultViewportScalingIndex";
Editor.Instance.ProjectCache.SetCustomData(defaultKey, _defaultScaleActiveIndex.ToString());
var customKey = $"{id}:CustomViewportScalingIndex";
Editor.Instance.ProjectCache.SetCustomData(customKey, _customScaleActiveIndex.ToString());
}
private void LoadCustomUIScalingOption()
{
if (!Prefab)
return;
var id = Prefab.ID;
Prefab.WaitForLoaded();
var defaultKey = $"{id}:DefaultViewportScalingIndex";
if (Editor.Instance.ProjectCache.TryGetCustomData(defaultKey, out string defaultData))
{
if (int.TryParse(defaultData, out var index))
{
var options = Editor.Instance.UI.DefaultViewportScaleOptions;
if (options.Count > index)
{
_defaultScaleActiveIndex = index;
if (index != -1)
ChangeUIView(Editor.Instance.UI.DefaultViewportScaleOptions[index]);
}
// Assume option does not exist anymore so move to default.
else if (index != -1)
{
_defaultScaleActiveIndex = 0;
}
}
}
var customKey = $"{id}:CustomViewportScalingIndex";
if (Editor.Instance.ProjectCache.TryGetCustomData(customKey, out string data))
{
if (int.TryParse(data, out var index))
{
var options = Editor.Instance.UI.CustomViewportScaleOptions;
if (options.Count > index)
{
_customScaleActiveIndex = index;
if (index != -1)
ChangeUIView(options[index]);
}
// Assume option does not exist anymore so move to default.
else if (index != -1)
{
_defaultScaleActiveIndex = 0;
_customScaleActiveIndex = -1;
}
}
}
}
private void OnUpdate(float deltaTime) private void OnUpdate(float deltaTime)
{ {
for (int i = 0; i < Gizmos.Count; i++) for (int i = 0; i < Gizmos.Count; i++)

View File

@@ -112,9 +112,8 @@ namespace FlaxEditor.Viewport.Previews
LinkCanvas(_instance); LinkCanvas(_instance);
// Link UI control to the preview // Link UI control to the preview
var uiControl = _instance as UIControl;
if (_uiControlLinked == null && if (_uiControlLinked == null &&
uiControl != null && _instance is UIControl uiControl &&
uiControl.Control != null && uiControl.Control != null &&
uiControl.Control.Parent == null) uiControl.Control.Parent == null)
{ {
@@ -129,12 +128,6 @@ namespace FlaxEditor.Viewport.Previews
_uiControlLinked.Control.Parent = _uiParentLink; _uiControlLinked.Control.Parent = _uiParentLink;
_hasUILinked = true; _hasUILinked = true;
} }
// Use UI mode when root is empty UI Control
if (_uiControlLinked == null && uiControl != null && uiControl.Control == null)
{
_hasUILinked = true;
}
} }
private void LinkCanvas(Actor actor) private void LinkCanvas(Actor actor)

View File

@@ -97,7 +97,6 @@ namespace FlaxEditor.Windows
"Jean-Baptiste Perrier", "Jean-Baptiste Perrier",
"Chandler Cox", "Chandler Cox",
"Ari Vuollet", "Ari Vuollet",
"Vincent Saarmann",
}); });
authors.Sort(); authors.Sort();
var authorsLabel = new Label(4, topParentControl.Bottom + 20, Width - 8, 70) var authorsLabel = new Label(4, topParentControl.Bottom + 20, Width - 8, 70)

View File

@@ -371,7 +371,6 @@ namespace FlaxEditor.Windows.Assets
else else
_viewport.SetInitialUIMode(_viewport._hasUILinked); _viewport.SetInitialUIMode(_viewport._hasUILinked);
_viewport.UIModeToggled += OnUIModeToggled; _viewport.UIModeToggled += OnUIModeToggled;
_viewport.CreateViewScalingOptions();
Graph.MainActor = _viewport.Instance; Graph.MainActor = _viewport.Instance;
Selection.Clear(); Selection.Clear();
Select(Graph.Main); Select(Graph.Main);
@@ -568,15 +567,6 @@ namespace FlaxEditor.Windows.Assets
Graph.Dispose(); Graph.Dispose();
} }
/// <inheritdoc />
protected override void OnClose()
{
// Save current UI view size state.
_viewport.SaveActiveUIScalingOption();
base.OnClose();
}
/// <inheritdoc /> /// <inheritdoc />
public EditorViewport PresenterViewport => _viewport; public EditorViewport PresenterViewport => _viewport;

View File

@@ -116,11 +116,6 @@ namespace FlaxEditor.Windows
if (InputOptions.WindowShortcutsAvaliable) if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.VisualScriptDebuggerWin.FocusOrShow(); Editor.Windows.VisualScriptDebuggerWin.FocusOrShow();
}); });
InputActions.Add(options => options.EditorOptionsWindow, () =>
{
if (InputOptions.WindowShortcutsAvaliable)
Editor.Windows.EditorOptionsWin.FocusOrShow();
});
// Register // Register
Editor.Windows.OnWindowAdd(this); Editor.Windows.OnWindowAdd(this);

View File

@@ -6,7 +6,6 @@ using System.Xml;
using FlaxEditor.Gizmo; using FlaxEditor.Gizmo;
using FlaxEditor.GUI.ContextMenu; using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.GUI.Input; using FlaxEditor.GUI.Input;
using FlaxEditor.Modules;
using FlaxEditor.Options; using FlaxEditor.Options;
using FlaxEngine; using FlaxEngine;
using FlaxEngine.GUI; using FlaxEngine.GUI;
@@ -35,8 +34,8 @@ namespace FlaxEditor.Windows
private CursorLockMode _cursorLockMode = CursorLockMode.None; private CursorLockMode _cursorLockMode = CursorLockMode.None;
// Viewport scaling variables // Viewport scaling variables
private int _defaultScaleActiveIndex = 0; private List<ViewportScaleOptions> _defaultViewportScaling = new List<ViewportScaleOptions>();
private int _customScaleActiveIndex = -1; private List<ViewportScaleOptions> _customViewportScaling = new List<ViewportScaleOptions>();
private float _viewportAspectRatio = 1; private float _viewportAspectRatio = 1;
private float _windowAspectRatio = 1; private float _windowAspectRatio = 1;
private bool _useAspect = false; private bool _useAspect = false;
@@ -247,6 +246,35 @@ namespace FlaxEditor.Windows
/// </summary> /// </summary>
public InterfaceOptions.PlayModeFocus FocusOnPlayOption { get; set; } public InterfaceOptions.PlayModeFocus FocusOnPlayOption { get; set; }
private enum ViewportScaleType
{
Resolution = 0,
Aspect = 1,
}
private class ViewportScaleOptions
{
/// <summary>
/// The name.
/// </summary>
public string Label;
/// <summary>
/// The Type of scaling to do.
/// </summary>
public ViewportScaleType ScaleType;
/// <summary>
/// The width and height to scale by.
/// </summary>
public Int2 Size;
/// <summary>
/// If the scaling is active.
/// </summary>
public bool Active;
}
private class PlayModeFocusOptions private class PlayModeFocusOptions
{ {
/// <summary> /// <summary>
@@ -392,7 +420,7 @@ namespace FlaxEditor.Windows
InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand()); InputActions.Add(options => options.FocusConsoleCommand, () => Editor.Instance.Windows.OutputLogWin.FocusCommand());
} }
private void ChangeViewportRatio(UIModule.ViewportScaleOption v) private void ChangeViewportRatio(ViewportScaleOptions v)
{ {
if (v == null) if (v == null)
return; return;
@@ -411,11 +439,11 @@ namespace FlaxEditor.Windows
{ {
switch (v.ScaleType) switch (v.ScaleType)
{ {
case UIModule.ViewportScaleOption.ViewportScaleType.Aspect: case ViewportScaleType.Aspect:
_useAspect = true; _useAspect = true;
_freeAspect = false; _freeAspect = false;
break; break;
case UIModule.ViewportScaleOption.ViewportScaleType.Resolution: case ViewportScaleType.Resolution:
_useAspect = false; _useAspect = false;
_freeAspect = false; _freeAspect = false;
break; break;
@@ -606,12 +634,49 @@ namespace FlaxEditor.Windows
// Viewport aspect ratio // Viewport aspect ratio
{ {
var vsMenu = menu.AddChildMenu("Viewport Size").ContextMenu; // Create default scaling options if they dont exist from deserialization.
Editor.UI.CreateViewportSizingContextMenu(vsMenu, _defaultScaleActiveIndex, _customScaleActiveIndex, false, ChangeViewportRatio, (a, b) => if (_defaultViewportScaling.Count == 0)
{ {
_defaultScaleActiveIndex = a; _defaultViewportScaling.Add(new ViewportScaleOptions
_customScaleActiveIndex = b; {
}); Label = "Free Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(1, 1),
Active = true,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "16:9 Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(16, 9),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "16:10 Aspect",
ScaleType = ViewportScaleType.Aspect,
Size = new Int2(16, 10),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "1920x1080 Resolution (Full HD)",
ScaleType = ViewportScaleType.Resolution,
Size = new Int2(1920, 1080),
Active = false,
});
_defaultViewportScaling.Add(new ViewportScaleOptions
{
Label = "2560x1440 Resolution (2K)",
ScaleType = ViewportScaleType.Resolution,
Size = new Int2(2560, 1440),
Active = false,
});
}
var vsMenu = menu.AddChildMenu("Viewport Size").ContextMenu;
CreateViewportSizingContextMenu(vsMenu);
} }
// Take Screenshot // Take Screenshot
@@ -709,6 +774,243 @@ namespace FlaxEditor.Windows
} }
} }
private void CreateViewportSizingContextMenu(ContextMenu vsMenu)
{
// Add default viewport sizing options
for (int i = 0; i < _defaultViewportScaling.Count; i++)
{
var viewportScale = _defaultViewportScaling[i];
var button = vsMenu.AddButton(viewportScale.Label);
button.CloseMenuOnClick = false;
button.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
button.Tag = viewportScale;
if (viewportScale.Active)
ChangeViewportRatio(viewportScale);
button.Clicked += () =>
{
if (button.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v)
{
if (cmb == button)
{
v.Active = true;
button.Icon = Style.Current.CheckBoxTick;
ChangeViewportRatio(v);
}
else if (v.Active)
{
cmb.Icon = SpriteHandle.Invalid;
v.Active = false;
}
}
}
};
}
if (_defaultViewportScaling.Count != 0)
vsMenu.AddSeparator();
// Add custom viewport options
for (int i = 0; i < _customViewportScaling.Count; i++)
{
var viewportScale = _customViewportScaling[i];
var childCM = vsMenu.AddChildMenu(viewportScale.Label);
childCM.CloseMenuOnClick = false;
childCM.Icon = viewportScale.Active ? Style.Current.CheckBoxTick : SpriteHandle.Invalid;
childCM.Tag = viewportScale;
if (viewportScale.Active)
ChangeViewportRatio(viewportScale);
var applyButton = childCM.ContextMenu.AddButton("Apply");
applyButton.Tag = childCM.Tag = viewportScale;
applyButton.CloseMenuOnClick = false;
applyButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
// Reset selected icon on all buttons
foreach (var child in vsMenu.Items)
{
if (child is ContextMenuButton cmb && cmb.Tag is ViewportScaleOptions v)
{
if (child == childCM)
{
v.Active = true;
childCM.Icon = Style.Current.CheckBoxTick;
ChangeViewportRatio(v);
}
else if (v.Active)
{
cmb.Icon = SpriteHandle.Invalid;
v.Active = false;
}
}
}
};
var deleteButton = childCM.ContextMenu.AddButton("Delete");
deleteButton.CloseMenuOnClick = false;
deleteButton.Clicked += () =>
{
if (childCM.Tag == null)
return;
var v = (ViewportScaleOptions)childCM.Tag;
if (v.Active)
{
v.Active = false;
_defaultViewportScaling[0].Active = true;
ChangeViewportRatio(_defaultViewportScaling[0]);
}
_customViewportScaling.Remove(v);
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu);
vsMenu.PerformLayout();
};
}
if (_customViewportScaling.Count != 0)
vsMenu.AddSeparator();
// Add button
var add = vsMenu.AddButton("Add...");
add.CloseMenuOnClick = false;
add.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(add, new Float2(add.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var typeLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Type",
HorizontalAlignment = TextAlignment.Near,
};
typeLabel.LocalX += 10;
typeLabel.LocalY += 35;
var typeDropdown = new Dropdown
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Items = { "Aspect", "Resolution" },
SelectedItem = "Aspect",
Width = nameTextBox.Width
};
typeDropdown.LocalY += 35;
typeDropdown.LocalX += 100;
var whLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Width & Height",
HorizontalAlignment = TextAlignment.Near,
};
whLabel.LocalX += 10;
whLabel.LocalY += 60;
var wValue = new IntValueBox(16)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
wValue.LocalY += 60;
wValue.LocalX += 100;
var hValue = new IntValueBox(9)
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
MinValue = 1,
Width = 55,
};
hValue.LocalY += 60;
hValue.LocalX += 165;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Submit",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
Enum.TryParse(typeDropdown.SelectedItem, out ViewportScaleType type);
var combineString = type == ViewportScaleType.Aspect ? ":" : "x";
var name = nameTextBox.Text + " (" + wValue.Value + combineString + hValue.Value + ") " + typeDropdown.SelectedItem;
var newViewportOption = new ViewportScaleOptions
{
ScaleType = type,
Label = name,
Size = new Int2(wValue.Value, hValue.Value),
};
_customViewportScaling.Add(newViewportOption);
vsMenu.DisposeAllItems();
CreateViewportSizingContextMenu(vsMenu);
vsMenu.PerformLayout();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
typeDropdown.SelectedItem = "Aspect";
hValue.Value = 9;
wValue.Value = 16;
popup.Hide();
};
};
}
/// <inheritdoc /> /// <inheritdoc />
public override void Draw() public override void Draw()
{ {
@@ -889,12 +1191,12 @@ namespace FlaxEditor.Windows
if (!_cursorVisible) if (!_cursorVisible)
Screen.CursorVisible = true; Screen.CursorVisible = true;
Screen.CursorLock = CursorLockMode.None; Screen.CursorLock = CursorLockMode.None;
}
if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null) if (Editor.IsPlayMode && IsDocked && IsSelected && RootWindow.FocusedControl == null)
{ {
// Game UI cleared focus so regain it to maintain UI navigation just like game window does // Game UI cleared focus so regain it to maintain UI navigation just like game window does
FlaxEngine.Scripting.InvokeOnUpdate(Focus); FlaxEngine.Scripting.InvokeOnUpdate(Focus);
}
} }
} }
@@ -935,8 +1237,8 @@ namespace FlaxEditor.Windows
writer.WriteAttributeString("ShowGUI", ShowGUI.ToString()); writer.WriteAttributeString("ShowGUI", ShowGUI.ToString());
writer.WriteAttributeString("EditGUI", EditGUI.ToString()); writer.WriteAttributeString("EditGUI", EditGUI.ToString());
writer.WriteAttributeString("ShowDebugDraw", ShowDebugDraw.ToString()); writer.WriteAttributeString("ShowDebugDraw", ShowDebugDraw.ToString());
writer.WriteAttributeString("DefaultViewportScalingIndex", _defaultScaleActiveIndex.ToString()); writer.WriteAttributeString("DefaultViewportScaling", JsonSerializer.Serialize(_defaultViewportScaling));
writer.WriteAttributeString("CustomViewportScalingIndex", _customScaleActiveIndex.ToString()); writer.WriteAttributeString("CustomViewportScaling", JsonSerializer.Serialize(_customViewportScaling));
} }
/// <inheritdoc /> /// <inheritdoc />
@@ -948,30 +1250,22 @@ namespace FlaxEditor.Windows
EditGUI = value1; EditGUI = value1;
if (bool.TryParse(node.GetAttribute("ShowDebugDraw"), out value1)) if (bool.TryParse(node.GetAttribute("ShowDebugDraw"), out value1))
ShowDebugDraw = value1; ShowDebugDraw = value1;
if (int.TryParse(node.GetAttribute("DefaultViewportScalingIndex"), out int value2)) if (node.HasAttribute("CustomViewportScaling"))
_defaultScaleActiveIndex = value2; _customViewportScaling = JsonSerializer.Deserialize<List<ViewportScaleOptions>>(node.GetAttribute("CustomViewportScaling"));
if (int.TryParse(node.GetAttribute("CustomViewportScalingIndex"), out value2))
_customScaleActiveIndex = value2;
if (_defaultScaleActiveIndex != -1) for (int i = 0; i < _customViewportScaling.Count; i++)
{ {
var options = Editor.UI.DefaultViewportScaleOptions; if (_customViewportScaling[i].Active)
if (options.Count > _defaultScaleActiveIndex) ChangeViewportRatio(_customViewportScaling[i]);
ChangeViewportRatio(options[_defaultScaleActiveIndex]);
else
_defaultScaleActiveIndex = 0;
} }
if (_customScaleActiveIndex != -1) if (node.HasAttribute("DefaultViewportScaling"))
_defaultViewportScaling = JsonSerializer.Deserialize<List<ViewportScaleOptions>>(node.GetAttribute("DefaultViewportScaling"));
for (int i = 0; i < _defaultViewportScaling.Count; i++)
{ {
var options = Editor.UI.CustomViewportScaleOptions; if (_defaultViewportScaling[i].Active)
if (options.Count > _customScaleActiveIndex) ChangeViewportRatio(_defaultViewportScaling[i]);
ChangeViewportRatio(options[_customScaleActiveIndex]);
else
{
_defaultScaleActiveIndex = 0;
_customScaleActiveIndex = -1;
}
} }
} }

View File

@@ -246,7 +246,7 @@ namespace FlaxEditor.Windows
}); });
var flags = DebugCommands.GetCommandFlags(command); var flags = DebugCommands.GetCommandFlags(command);
if (flags.HasFlag(DebugCommands.CommandFlags.Exec)) if (flags.HasFlag(DebugCommands.CommandFlags.Exec))
lastItem.TintColor = new Color(0.75f, 0.75f, 1.0f, 1.0f); lastItem.TintColor = new Color(0.85f, 0.85f, 1.0f, 1.0f);
else if (flags.HasFlag(DebugCommands.CommandFlags.Read) && !flags.HasFlag(DebugCommands.CommandFlags.Write)) else if (flags.HasFlag(DebugCommands.CommandFlags.Read) && !flags.HasFlag(DebugCommands.CommandFlags.Write))
lastItem.TintColor = new Color(0.85f, 0.85f, 0.85f, 1.0f); lastItem.TintColor = new Color(0.85f, 0.85f, 0.85f, 1.0f);
lastItem.Focused += item => lastItem.Focused += item =>
@@ -320,25 +320,12 @@ namespace FlaxEditor.Windows
// Show commands search popup based on current text input // Show commands search popup based on current text input
var text = Text.Trim(); var text = Text.Trim();
bool isWhitespaceOnly = string.IsNullOrWhiteSpace(Text) && !string.IsNullOrEmpty(Text); if (text.Length != 0)
if (text.Length != 0 || isWhitespaceOnly)
{ {
DebugCommands.Search(text, out var matches); DebugCommands.Search(text, out var matches);
if (matches.Length != 0 || isWhitespaceOnly) if (matches.Length != 0)
{ {
string[] commands = []; ShowPopup(ref _searchPopup, matches, text);
if (isWhitespaceOnly)
DebugCommands.GetAllCommands(out commands);
ShowPopup(ref _searchPopup, isWhitespaceOnly ? commands : matches, text);
if (isWhitespaceOnly)
{
// Scroll to and select first item for consistent behaviour
var firstItem = _searchPopup.ItemsPanel.Children[0] as Item;
_searchPopup.ScrollToAndHighlightItemByName(firstItem.Name);
}
return; return;
} }
} }

View File

@@ -93,7 +93,6 @@ void MultiBlendBucketInit(AnimGraphInstanceData::Bucket& bucket)
void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket) void BlendPoseBucketInit(AnimGraphInstanceData::Bucket& bucket)
{ {
bucket.BlendPose.TransitionPosition = 0.0f; bucket.BlendPose.TransitionPosition = 0.0f;
bucket.BlendPose.BlendPoseIndex = -1;
bucket.BlendPose.PreviousBlendPoseIndex = -1; bucket.BlendPose.PreviousBlendPoseIndex = -1;
} }

View File

@@ -239,8 +239,7 @@ public:
struct BlendPoseBucket struct BlendPoseBucket
{ {
float TransitionPosition; float TransitionPosition;
int16 BlendPoseIndex; int32 PreviousBlendPoseIndex;
int16 PreviousBlendPoseIndex;
}; };
struct StateMachineBucket struct StateMachineBucket
@@ -811,7 +810,6 @@ public:
{ {
// Copy the node transformations // Copy the node transformations
Platform::MemoryCopy(dstNodes->Nodes.Get(), srcNodes->Nodes.Get(), sizeof(Transform) * _skeletonNodesCount); Platform::MemoryCopy(dstNodes->Nodes.Get(), srcNodes->Nodes.Get(), sizeof(Transform) * _skeletonNodesCount);
dstNodes->RootMotion = srcNodes->RootMotion;
// Copy the animation playback state // Copy the animation playback state
dstNodes->Position = srcNodes->Position; dstNodes->Position = srcNodes->Position;

View File

@@ -676,12 +676,9 @@ Variant AnimGraphExecutor::Blend(AnimGraphNode* node, const Value& poseA, const
if (!ANIM_GRAPH_IS_VALID_PTR(poseB)) if (!ANIM_GRAPH_IS_VALID_PTR(poseB))
nodesB = GetEmptyNodes(); nodesB = GetEmptyNodes();
const Transform* srcA = nodesA->Nodes.Get();
const Transform* srcB = nodesB->Nodes.Get();
Transform* dst = nodes->Nodes.Get();
for (int32 i = 0; i < nodes->Nodes.Count(); i++) for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{ {
Transform::Lerp(srcA[i], srcB[i], alpha, dst[i]); Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
} }
Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion); Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion);
nodes->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha); nodes->Position = Math::Lerp(nodesA->Position, nodesB->Position, alpha);
@@ -1266,7 +1263,21 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
{ {
const auto valueA = tryGetValue(node->GetBox(1), Value::Null); const auto valueA = tryGetValue(node->GetBox(1), Value::Null);
const auto valueB = tryGetValue(node->GetBox(2), Value::Null); const auto valueB = tryGetValue(node->GetBox(2), Value::Null);
value = Blend(node, valueA, valueB, alpha, AlphaBlendMode::Linear); const auto nodes = node->GetNodes(this);
auto nodesA = static_cast<AnimGraphImpulse*>(valueA.AsPointer);
auto nodesB = static_cast<AnimGraphImpulse*>(valueB.AsPointer);
if (!ANIM_GRAPH_IS_VALID_PTR(valueA))
nodesA = GetEmptyNodes();
if (!ANIM_GRAPH_IS_VALID_PTR(valueB))
nodesB = GetEmptyNodes();
for (int32 i = 0; i < nodes->Nodes.Count(); i++)
{
Transform::Lerp(nodesA->Nodes[i], nodesB->Nodes[i], alpha, nodes->Nodes[i]);
}
Transform::Lerp(nodesA->RootMotion, nodesB->RootMotion, alpha, nodes->RootMotion);
value = nodes;
} }
break; break;
@@ -1747,38 +1758,35 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
// [2]: int Pose Count // [2]: int Pose Count
// [3]: AlphaBlendMode Mode // [3]: AlphaBlendMode Mode
// Prepare
auto& bucket = context.Data->State[node->BucketIndex].BlendPose; auto& bucket = context.Data->State[node->BucketIndex].BlendPose;
const int16 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]); const int32 poseIndex = (int32)tryGetValue(node->GetBox(1), node->Values[0]);
const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]); const float blendDuration = (float)tryGetValue(node->GetBox(2), node->Values[1]);
const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses); const int32 poseCount = Math::Clamp(node->Values[2].AsInt, 0, MaxBlendPoses);
const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt; const AlphaBlendMode mode = (AlphaBlendMode)node->Values[3].AsInt;
if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
break;
// Check if swap transition end points // Skip if nothing to blend
if (bucket.PreviousBlendPoseIndex == poseIndex && bucket.BlendPoseIndex != poseIndex && bucket.TransitionPosition >= ANIM_GRAPH_BLEND_THRESHOLD) if (poseCount == 0 || poseIndex < 0 || poseIndex >= poseCount)
{ {
bucket.TransitionPosition = blendDuration - bucket.TransitionPosition; break;
Swap(bucket.BlendPoseIndex, bucket.PreviousBlendPoseIndex);
} }
// Check if transition is not active (first update, pose not changing or transition ended) // Check if transition is not active (first update, pose not changing or transition ended)
bucket.TransitionPosition += context.DeltaTime; bucket.TransitionPosition += context.DeltaTime;
bucket.BlendPoseIndex = poseIndex;
if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD) if (bucket.PreviousBlendPoseIndex == -1 || bucket.PreviousBlendPoseIndex == poseIndex || bucket.TransitionPosition >= blendDuration || blendDuration <= ANIM_GRAPH_BLEND_THRESHOLD)
{ {
bucket.TransitionPosition = 0.0f; bucket.TransitionPosition = 0.0f;
bucket.BlendPoseIndex = poseIndex;
bucket.PreviousBlendPoseIndex = poseIndex; bucket.PreviousBlendPoseIndex = poseIndex;
value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null); value = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
break; break;
} }
ASSERT(bucket.PreviousBlendPoseIndex >= 0 && bucket.PreviousBlendPoseIndex < poseCount);
// Blend two animations // Blend two animations
{ {
const float alpha = bucket.TransitionPosition / blendDuration; const float alpha = bucket.TransitionPosition / blendDuration;
const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null); const auto valueA = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.PreviousBlendPoseIndex), Value::Null);
const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + bucket.BlendPoseIndex), Value::Null); const auto valueB = tryGetValue(node->GetBox(FirstBlendPoseBoxIndex + poseIndex), Value::Null);
value = Blend(node, valueA, valueB, alpha, mode); value = Blend(node, valueA, valueB, alpha, mode);
} }

View File

@@ -23,11 +23,11 @@ void AudioListener::Update()
{ {
// Update the velocity // Update the velocity
const Vector3 pos = GetPosition(); const Vector3 pos = GetPosition();
const float dt = Math::Max(Time::Update.UnscaledDeltaTime.GetTotalSeconds(), 0.00001f); const float dt = Time::Update.UnscaledDeltaTime.GetTotalSeconds();
const auto prevVelocity = _velocity; const auto prevVelocity = _velocity;
_velocity = (pos - _prevPos) / dt; _velocity = (pos - _prevPos) / dt;
_prevPos = pos; _prevPos = pos;
if (_velocity != prevVelocity && !_velocity.IsNanOrInfinity()) if (_velocity != prevVelocity)
{ {
AudioBackend::Listener::VelocityChanged(_velocity); AudioBackend::Listener::VelocityChanged(_velocity);
} }

View File

@@ -168,8 +168,8 @@ void AudioSource::Play()
} }
else else
{ {
// Source was not properly added to the Audio Backend // Source was nt properly added to the Audio Backend
LOG(Warning, "Cannot play uninitialized audio source."); LOG(Warning, "Cannot play unitialized audio source.");
} }
} }
@@ -408,9 +408,6 @@ void AudioSource::Update()
_startingToPlay = false; _startingToPlay = false;
} }
if (Math::NearEqual(GetTime(), _startTime) && _isActuallyPlayingSth && _startingToPlay)
ClipStarted();
if (!UseStreaming() && Math::NearEqual(GetTime(), 0.0f) && _isActuallyPlayingSth && !_startingToPlay) if (!UseStreaming() && Math::NearEqual(GetTime(), 0.0f) && _isActuallyPlayingSth && !_startingToPlay)
{ {
int32 queuedBuffers; int32 queuedBuffers;
@@ -426,7 +423,6 @@ void AudioSource::Update()
{ {
Stop(); Stop();
} }
ClipFinished();
} }
} }
@@ -497,7 +493,6 @@ void AudioSource::Update()
{ {
Stop(); Stop();
} }
ClipFinished();
} }
ASSERT(_streamingFirstChunk < clip->Buffers.Count()); ASSERT(_streamingFirstChunk < clip->Buffers.Count());

View File

@@ -76,16 +76,6 @@ public:
API_FIELD(Attributes="EditorOrder(10), DefaultValue(null), EditorDisplay(\"Audio Source\")") API_FIELD(Attributes="EditorOrder(10), DefaultValue(null), EditorDisplay(\"Audio Source\")")
AssetReference<AudioClip> Clip; AssetReference<AudioClip> Clip;
/// <summary>
/// Event fired when the audio clip starts.
/// </summary>
API_EVENT() Action ClipStarted;
/// <summary>
/// Event fired when the audio clip finishes.
/// </summary>
API_EVENT() Action ClipFinished;
/// <summary> /// <summary>
/// Gets the velocity of the source. Determines pitch in relation to AudioListener's position. Only relevant for spatial (3D) sources. /// Gets the velocity of the source. Determines pitch in relation to AudioListener's position. Only relevant for spatial (3D) sources.
/// </summary> /// </summary>

View File

@@ -600,6 +600,7 @@ void Animation::OnScriptingDispose()
Asset::LoadResult Animation::load() Asset::LoadResult Animation::load()
{ {
PROFILE_MEM(AnimationsData); PROFILE_MEM(AnimationsData);
ScopeWriteLock systemScope(Animations::SystemLocker);
// Get stream with animations data // Get stream with animations data
const auto dataChunk = GetChunk(0); const auto dataChunk = GetChunk(0);

View File

@@ -27,6 +27,7 @@ AnimationGraph::AnimationGraph(const SpawnParams& params, const AssetInfo* info)
Asset::LoadResult AnimationGraph::load() Asset::LoadResult AnimationGraph::load()
{ {
PROFILE_MEM(AnimationsData); PROFILE_MEM(AnimationsData);
ScopeWriteLock systemScope(Animations::SystemLocker);
// Get stream with graph data // Get stream with graph data
const auto surfaceChunk = GetChunk(0); const auto surfaceChunk = GetChunk(0);
@@ -85,6 +86,7 @@ bool AnimationGraph::InitAsAnimation(SkinnedModel* baseModel, Animation* anim, b
return true; return true;
} }
PROFILE_MEM(AnimationsData); PROFILE_MEM(AnimationsData);
ScopeWriteLock systemScope(Animations::SystemLocker);
// Create Graph data // Create Graph data
MemoryWriteStream writeStream(512); MemoryWriteStream writeStream(512);
@@ -170,6 +172,7 @@ bool AnimationGraph::SaveSurface(const BytesContainer& data)
{ {
if (OnCheckSave()) if (OnCheckSave())
return true; return true;
ScopeWriteLock systemScope(Animations::SystemLocker);
ScopeLock lock(Locker); ScopeLock lock(Locker);
if (IsVirtual()) if (IsVirtual())

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