diff --git a/GenerateProjectFiles.bat b/GenerateProjectFiles.bat index 1b766457f..622939c34 100644 --- a/GenerateProjectFiles.bat +++ b/GenerateProjectFiles.bat @@ -1,15 +1,22 @@ @echo off - -rem Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. +:: Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. setlocal pushd + echo Generating Flax Engine project files... -rem Run Flax.Build to generate Visual Studio solution and project files (also pass the arguments) -call "Development\Scripts\Windows\CallBuildTool.bat" -genproject %* +:: Change the path to the script root +cd /D "%~dp0" + +:: Run Flax.Build to generate Visual Studio solution and project files (also pass the arguments) +call "Development\Scripts\Windows\CallBuildTool.bat" -genproject %* if errorlevel 1 goto BuildToolFailed +:: Build bindings for all editor configurations +echo Building C# bindings... +Binaries\Tools\Flax.Build.exe -build -BuildBindingsOnly -arch=x64 -platform=Windows --buildTargets=FlaxEditor,FlaxGame + popd echo Done! exit /B 0 diff --git a/GenerateProjectFiles.command b/GenerateProjectFiles.command index 6554886bc..5ee5c0783 100755 --- a/GenerateProjectFiles.command +++ b/GenerateProjectFiles.command @@ -10,3 +10,8 @@ cd "`dirname "$0"`" # Run Flax.Build to generate project files (also pass the arguments) bash ./Development/Scripts/Mac/CallBuildTool.sh --genproject "$@" + +# Build bindings for all editor configurations +echo Building C# bindings... +# TODO: Detect the correct architecture here +Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=ARM64 -platform=Mac --buildTargets=FlaxEditor,FlaxGame diff --git a/GenerateProjectFiles.sh b/GenerateProjectFiles.sh index fcda1acc1..dceb8abe8 100755 --- a/GenerateProjectFiles.sh +++ b/GenerateProjectFiles.sh @@ -10,3 +10,8 @@ cd "`dirname "$0"`" # Run Flax.Build to generate project files (also pass the arguments) bash ./Development/Scripts/Linux/CallBuildTool.sh --genproject "$@" + +# Build bindings for all editor configurations +echo Building C# bindings... +# TODO: Detect the correct architecture here +Binaries/Tools/Flax.Build -build -BuildBindingsOnly -arch=x64 -platform=Linux --buildTargets=FlaxEditor,FlaxGame diff --git a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs index ad76ac295..d7bfbbad7 100644 --- a/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/ScriptsEditor.cs @@ -25,6 +25,7 @@ namespace FlaxEditor.CustomEditors.Dedicated private DragHandlers _dragHandlers; private DragScriptItems _dragScripts; private DragAssets _dragAssets; + private Button _addScriptsButton; /// /// The parent scripts editor. @@ -40,16 +41,19 @@ namespace FlaxEditor.CustomEditors.Dedicated AutoFocus = false; // Add script button - float addScriptButtonWidth = 60.0f; - var addScriptButton = new Button + var buttonText = "Add script"; + var textSize = Style.Current.FontMedium.MeasureText(buttonText); + float addScriptButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4; + var buttonHeight = (textSize.Y < 18) ? 18 : textSize.Y + 4; + _addScriptsButton = new Button { TooltipText = "Add new scripts to the actor", AnchorPreset = AnchorPresets.MiddleCenter, - Text = "Add script", + Text = buttonText, Parent = this, - Bounds = new Rectangle((Width - addScriptButtonWidth) / 2, 1, addScriptButtonWidth, 18), + Bounds = new Rectangle((Width - addScriptButtonWidth) / 2, 1, addScriptButtonWidth, buttonHeight), }; - addScriptButton.ButtonClicked += OnAddScriptButtonClicked; + _addScriptsButton.ButtonClicked += OnAddScriptButtonClicked; } private void OnAddScriptButtonClicked(Button button) @@ -82,7 +86,7 @@ namespace FlaxEditor.CustomEditors.Dedicated var size = Size; // Info - Render2D.DrawText(style.FontSmall, "Drag scripts here", new Rectangle(2, 22, size.X - 4, size.Y - 4 - 20), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center); + Render2D.DrawText(style.FontSmall, "Drag scripts here", new Rectangle(2, _addScriptsButton.Height + 4, size.X - 4, size.Y - 4 - 20), style.ForegroundDisabled, TextAlignment.Center, TextAlignment.Center); // Check if drag is over if (IsDragOver && _dragHandlers != null && _dragHandlers.HasValidDrag) @@ -554,8 +558,8 @@ namespace FlaxEditor.CustomEditors.Dedicated return; for (int j = 0; j < e.Length; j++) { - var t1 = scripts[j]?.TypeName; - var t2 = e[j]?.TypeName; + var t1 = scripts[j] != null ? scripts[j].TypeName : null; + var t2 = e[j] != null ? e[j].TypeName : null; if (t1 != t2) return; } diff --git a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs index fde4967e8..5215e23a4 100644 --- a/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs +++ b/Source/Editor/CustomEditors/Dedicated/UIControlEditor.cs @@ -422,12 +422,14 @@ namespace FlaxEditor.CustomEditors.Dedicated // Set control type button var space = layout.Space(20); - float setTypeButtonWidth = 60.0f; + var buttonText = "Set Type"; + var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText); + float setTypeButtonWidth = (textSize.X < 60.0f) ? 60.0f : textSize.X + 4; var setTypeButton = new Button { TooltipText = "Sets the control to the given type", AnchorPreset = AnchorPresets.MiddleCenter, - Text = "Set Type", + Text = buttonText, Parent = space.Spacer, Bounds = new Rectangle((space.Spacer.Width - setTypeButtonWidth) / 2, 1, setTypeButtonWidth, 18), }; diff --git a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs index cb4e7b9c1..4aa02ac78 100644 --- a/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs +++ b/Source/Editor/CustomEditors/Editors/ActorTransformEditor.cs @@ -88,20 +88,20 @@ namespace FlaxEditor.CustomEditors.Editors LinkValues = Editor.Instance.Windows.PropertiesWin.ScaleLinked; // Add button with the link icon + _linkButton = new Button { BackgroundBrush = new SpriteBrush(Editor.Instance.Icons.Link32), Parent = LinkedLabel, Width = 18, Height = 18, - AnchorPreset = AnchorPresets.TopLeft, + AnchorPreset = AnchorPresets.MiddleLeft, }; _linkButton.Clicked += ToggleLink; ToggleEnabled(); SetLinkStyle(); - var x = LinkedLabel.Text.Value.Length * 7 + 5; - _linkButton.LocalX += x; - _linkButton.LocalY += 1; + var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(LinkedLabel.Text.Value); + _linkButton.LocalX += textSize.X + 10; LinkedLabel.SetupContextMenu += (label, menu, editor) => { menu.AddSeparator(); diff --git a/Source/Editor/CustomEditors/Editors/BooleanEditor.cs b/Source/Editor/CustomEditors/Editors/BooleanEditor.cs index f5edafed8..803b7b4dd 100644 --- a/Source/Editor/CustomEditors/Editors/BooleanEditor.cs +++ b/Source/Editor/CustomEditors/Editors/BooleanEditor.cs @@ -34,7 +34,9 @@ namespace FlaxEditor.CustomEditors.Editors } else { - element.CheckBox.Checked = (bool)Values[0]; + var value = (bool?)Values[0]; + if (value != null) + element.CheckBox.Checked = value.Value; } } } diff --git a/Source/Editor/CustomEditors/Editors/TagEditor.cs b/Source/Editor/CustomEditors/Editors/TagEditor.cs index 61e0bba7d..911397785 100644 --- a/Source/Editor/CustomEditors/Editors/TagEditor.cs +++ b/Source/Editor/CustomEditors/Editors/TagEditor.cs @@ -623,13 +623,18 @@ namespace FlaxEditor.CustomEditors.Editors { _label = layout.ClickableLabel(GetText(out _)).CustomControl; _label.RightClick += ShowPicker; + var buttonText = "..."; var button = new Button { Size = new Float2(16.0f), - Text = "...", + Text = buttonText, TooltipText = "Edit...", Parent = _label, }; + var textSize = FlaxEngine.GUI.Style.Current.FontMedium.MeasureText(buttonText); + if (textSize.Y > button.Width) + button.Width = textSize.Y + 2; + button.SetAnchorPreset(AnchorPresets.MiddleRight, false, true); button.Clicked += ShowPicker; } diff --git a/Source/Editor/EditorAssets.cs b/Source/Editor/EditorAssets.cs index 7fa920ca6..eb2f21356 100644 --- a/Source/Editor/EditorAssets.cs +++ b/Source/Editor/EditorAssets.cs @@ -36,7 +36,9 @@ namespace FlaxEditor public static void OnEditorOptionsChanged(Options.EditorOptions options) { - var param = _highlightMaterial?.GetParameter("Color"); + if (!_highlightMaterial) + return; + var param = _highlightMaterial.GetParameter("Color"); if (param != null) param.Value = options.Visual.HighlightColor; } diff --git a/Source/Editor/GUI/Row.cs b/Source/Editor/GUI/Row.cs index 8dad8b20d..b07d693e5 100644 --- a/Source/Editor/GUI/Row.cs +++ b/Source/Editor/GUI/Row.cs @@ -37,6 +37,9 @@ namespace FlaxEditor.GUI : base(0, 0, 100, height) { Depth = -1; + + if (Height < Style.Current.FontMedium.Height) + Height = Style.Current.FontMedium.Height + 4; } /// diff --git a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs index c5989cca5..76b6ca246 100644 --- a/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs +++ b/Source/Editor/GUI/Timeline/SceneAnimationTimeline.cs @@ -33,7 +33,7 @@ namespace FlaxEditor.GUI.Timeline /// public SceneAnimationPlayer Player { - get => _player; + get => _player != null ? _player : null; set { if (_player == value) @@ -268,7 +268,7 @@ namespace FlaxEditor.GUI.Timeline /// public override void OnSeek(int frame) { - if (_player?.Animation) + if (_player != null && _player.Animation) { _player.Animation.WaitForLoaded(); _player.Time = frame / _player.Animation.FramesPerSecond; diff --git a/Source/Editor/Modules/ProgressReportingModule.cs b/Source/Editor/Modules/ProgressReportingModule.cs index 16acd7f8b..22ae5ea98 100644 --- a/Source/Editor/Modules/ProgressReportingModule.cs +++ b/Source/Editor/Modules/ProgressReportingModule.cs @@ -129,6 +129,7 @@ namespace FlaxEditor.Modules else { Editor.UI.UpdateProgress(string.Empty, 0); + Editor.UI.UpdateStatusBar(); } } diff --git a/Source/Editor/Modules/UIModule.cs b/Source/Editor/Modules/UIModule.cs index 1bb40469b..299865dea 100644 --- a/Source/Editor/Modules/UIModule.cs +++ b/Source/Editor/Modules/UIModule.cs @@ -285,7 +285,7 @@ namespace FlaxEditor.Modules Color color; if (Editor.StateMachine.IsPlayMode) - color = Color.OrangeRed; + color = Style.Current.Statusbar.PlayMode; else color = Style.Current.BackgroundSelected; @@ -299,6 +299,11 @@ namespace FlaxEditor.Modules else text = "Ready"; + if(ProgressVisible) + { + color = Style.Current.Statusbar.Loading; + } + StatusBar.Text = text; StatusBar.StatusColor = color; _contentStats = contentStats; @@ -344,7 +349,7 @@ namespace FlaxEditor.Modules internal void ProgressFailed(string message) { _progressFailed = true; - StatusBar.StatusColor = Color.Red; + StatusBar.StatusColor = Style.Current.Statusbar.Failed; StatusBar.Text = message; _outputLogButton.Visible = true; } @@ -397,6 +402,10 @@ namespace FlaxEditor.Modules { UpdateStatusBar(); } + else if(ProgressVisible) + { + UpdateStatusBar(); + } } private class CustomWindowBorderControl : Control @@ -778,7 +787,7 @@ namespace FlaxEditor.Modules HorizontalAlignment = TextAlignment.Far, AnchorPreset = AnchorPresets.HorizontalStretchMiddle, Parent = progressPanel, - Offsets = new Margin(progressBarRightMargin, progressBarWidth + progressBarLeftMargin + progressBarRightMargin, 0, 0), + Offsets = new Margin(progressBarRightMargin, progressBarWidth + progressBarLeftMargin + progressBarRightMargin, 0, 0) }; UpdateStatusBar(); diff --git a/Source/Editor/Modules/WindowsModule.cs b/Source/Editor/Modules/WindowsModule.cs index 086772ca2..d0c8b9747 100644 --- a/Source/Editor/Modules/WindowsModule.cs +++ b/Source/Editor/Modules/WindowsModule.cs @@ -721,7 +721,7 @@ namespace FlaxEditor.Modules // Create main window var settings = CreateWindowSettings.Default; settings.Title = "Flax Editor"; - //settings.Size = Platform.DesktopSize; + settings.Size = Platform.DesktopSize * 0.75f; settings.StartPosition = WindowStartPosition.CenterScreen; settings.ShowAfterFirstPaint = true; diff --git a/Source/Editor/Options/OptionsModule.cs b/Source/Editor/Options/OptionsModule.cs index 68aa11626..c2d744239 100644 --- a/Source/Editor/Options/OptionsModule.cs +++ b/Source/Editor/Options/OptionsModule.cs @@ -244,6 +244,13 @@ namespace FlaxEditor.Options CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC), ProgressNormal = Color.FromBgra(0xFF0ad328), + Statusbar = new Style.StatusbarStyle() + { + PlayMode = Color.FromBgra(0xFF2F9135), + Failed = Color.FromBgra(0xFF9C2424), + Loading = Color.FromBgra(0xFF2D2D30) + }, + // Fonts FontTitle = options.Interface.TitleFont.GetFont(), FontLarge = options.Interface.LargeFont.GetFont(), diff --git a/Source/Editor/Surface/Elements/OutputBox.cs b/Source/Editor/Surface/Elements/OutputBox.cs index 36355e5a5..b6efa1aa3 100644 --- a/Source/Editor/Surface/Elements/OutputBox.cs +++ b/Source/Editor/Surface/Elements/OutputBox.cs @@ -41,10 +41,8 @@ namespace FlaxEditor.Surface.Elements } // Calculate control points - var dst = (end - start) * new Float2(0.5f, 0.05f); - var control1 = new Float2(start.X + dst.X, start.Y + dst.Y); - var control2 = new Float2(end.X - dst.X, end.Y + dst.Y); - + CalculateBezierControlPoints(start, end, out var control1, out var control2); + // Draw line Render2D.DrawBezier(start, control1, control2, end, color, thickness); @@ -56,6 +54,23 @@ namespace FlaxEditor.Surface.Elements */ } + private static void CalculateBezierControlPoints(Float2 start, Float2 end, out Float2 control1, out Float2 control2) + { + // Control points parameters + const float minControlLength = 100f; + const float maxControlLength = 150f; + var dst = (end - start).Length; + var yDst = Mathf.Abs(start.Y - end.Y); + + // Calculate control points + var minControlDst = dst * 0.5f; + var maxControlDst = Mathf.Max(Mathf.Min(maxControlLength, dst), minControlLength); + var controlDst = Mathf.Lerp(minControlDst, maxControlDst, Mathf.Clamp(yDst / minControlLength, 0f, 1f)); + + control1 = new Float2(start.X + controlDst, start.Y); + control2 = new Float2(end.X - controlDst, end.Y); + } + /// /// Checks if a point intersects a connection /// @@ -82,13 +97,9 @@ namespace FlaxEditor.Surface.Elements float offset = Mathf.Sign(end.Y - start.Y) * distance; if ((point.Y - (start.Y - offset)) * ((end.Y + offset) - point.Y) < 0) return false; - - // Taken from the Render2D.DrawBezier code + float squaredDistance = distance; - - var dst = (end - start) * new Float2(0.5f, 0.05f); - var control1 = new Float2(start.X + dst.X, start.Y + dst.Y); - var control2 = new Float2(end.X - dst.X, end.Y + dst.Y); + CalculateBezierControlPoints(start, end, out var control1, out var control2); var d1 = control1 - start; var d2 = control2 - control1; diff --git a/Source/Editor/Tools/Foliage/FoliageTab.cs b/Source/Editor/Tools/Foliage/FoliageTab.cs index fe5412118..1b46a42be 100644 --- a/Source/Editor/Tools/Foliage/FoliageTab.cs +++ b/Source/Editor/Tools/Foliage/FoliageTab.cs @@ -137,14 +137,23 @@ namespace FlaxEditor.Tools.Foliage Offsets = Margin.Zero, Parent = _noFoliagePanel }; + + var buttonText = "Create new foliage"; _createNewFoliage = new Button { - Text = "Create new foliage", + Text = buttonText, AnchorPreset = AnchorPresets.MiddleCenter, Offsets = new Margin(-60, 120, -12, 24), Parent = _noFoliagePanel, Enabled = false }; + var textSize = Style.Current.FontMedium.MeasureText(buttonText); + if (_createNewFoliage.Width < textSize.X) + { + _createNewFoliage.LocalX -= (textSize.X - _createNewFoliage.Width) / 2; + _createNewFoliage.Width = textSize.X + 6; + } + _createNewFoliage.Clicked += OnCreateNewFoliageClicked; } diff --git a/Source/Editor/Tools/Foliage/FoliageTypesTab.cs b/Source/Editor/Tools/Foliage/FoliageTypesTab.cs index 2a51d972c..8934f5058 100644 --- a/Source/Editor/Tools/Foliage/FoliageTypesTab.cs +++ b/Source/Editor/Tools/Foliage/FoliageTypesTab.cs @@ -375,7 +375,7 @@ namespace FlaxEditor.Tools.Foliage private void OnModified() { - Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage?.Scene); + Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage != null ? _proxy.Foliage.Scene : null); } private void OnSelectedFoliageChanged() diff --git a/Source/Editor/Tools/Foliage/PaintTab.cs b/Source/Editor/Tools/Foliage/PaintTab.cs index e4f01661b..ba31ca18b 100644 --- a/Source/Editor/Tools/Foliage/PaintTab.cs +++ b/Source/Editor/Tools/Foliage/PaintTab.cs @@ -218,7 +218,7 @@ namespace FlaxEditor.Tools.Foliage private void OnModified() { - Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage?.Scene); + Editor.Instance.Scene.MarkSceneEdited(_proxy.Foliage != null ? _proxy.Foliage.Scene : null); } private void OnSelectedFoliageChanged() diff --git a/Source/Editor/Tools/Terrain/CarveTab.cs b/Source/Editor/Tools/Terrain/CarveTab.cs index 6e0a9c6d3..d51915acf 100644 --- a/Source/Editor/Tools/Terrain/CarveTab.cs +++ b/Source/Editor/Tools/Terrain/CarveTab.cs @@ -95,14 +95,23 @@ namespace FlaxEditor.Tools.Terrain Offsets = Margin.Zero, Parent = _noTerrainPanel }; + + var buttonText = "Create new terrain"; _createTerrainButton = new Button { - Text = "Create new terrain", + Text = buttonText, AnchorPreset = AnchorPresets.MiddleCenter, Offsets = new Margin(-60, 120, -12, 24), Parent = _noTerrainPanel, Enabled = false }; + var textSize = Style.Current.FontMedium.MeasureText(buttonText); + if (_createTerrainButton.Width < textSize.X) + { + _createTerrainButton.LocalX -= (textSize.X - _createTerrainButton.Width) / 2; + _createTerrainButton.Width = textSize.X + 6; + } + _createTerrainButton.Clicked += OnCreateNewTerrainClicked; } diff --git a/Source/Editor/Tools/VertexPainting.cs b/Source/Editor/Tools/VertexPainting.cs index 30bb0c84f..3b2c53e6b 100644 --- a/Source/Editor/Tools/VertexPainting.cs +++ b/Source/Editor/Tools/VertexPainting.cs @@ -545,7 +545,7 @@ namespace FlaxEditor.Tools public override bool IsControllingMouse => IsPainting; /// - public override BoundingSphere FocusBounds => _selectedModel?.Sphere ?? base.FocusBounds; + public override BoundingSphere FocusBounds => _selectedModel != null ? _selectedModel.Sphere : base.FocusBounds; /// public override void Update(float dt) diff --git a/Source/Editor/Undo/Actions/PasteActorsAction.cs b/Source/Editor/Undo/Actions/PasteActorsAction.cs index 8b0d040d8..7aee40878 100644 --- a/Source/Editor/Undo/Actions/PasteActorsAction.cs +++ b/Source/Editor/Undo/Actions/PasteActorsAction.cs @@ -144,7 +144,7 @@ namespace FlaxEditor.Actions { var node = nodeParents[i]; var actor = node.Actor; - var parent = actor?.Parent; + var parent = actor != null ? actor.Parent : null; if (parent != null) { bool IsNameValid(string name) diff --git a/Source/Editor/Viewport/EditorViewport.cs b/Source/Editor/Viewport/EditorViewport.cs index 34dbe561c..8c71a8b02 100644 --- a/Source/Editor/Viewport/EditorViewport.cs +++ b/Source/Editor/Viewport/EditorViewport.cs @@ -441,6 +441,9 @@ namespace FlaxEditor.Viewport if (useWidgets) { + var largestText = "Invert Panning"; + var textSize = Style.Current.FontMedium.MeasureText(largestText); + var xLocationForExtras = textSize.X + 5; // Camera speed widget var camSpeed = new ViewportWidgetsContainer(ViewportWidgetLocation.UpperRight); var camSpeedCM = new ContextMenu(); @@ -541,7 +544,7 @@ namespace FlaxEditor.Viewport { var ortho = ViewWidgetButtonMenu.AddButton("Orthographic"); ortho.CloseMenuOnClick = false; - var orthoValue = new CheckBox(90, 2, _isOrtho) + var orthoValue = new CheckBox(xLocationForExtras, 2, _isOrtho) { Parent = ortho }; @@ -581,7 +584,7 @@ namespace FlaxEditor.Viewport { var fov = ViewWidgetButtonMenu.AddButton("Field Of View"); fov.CloseMenuOnClick = false; - var fovValue = new FloatValueBox(1, 90, 2, 70.0f, 35.0f, 160.0f, 0.1f) + var fovValue = new FloatValueBox(1, xLocationForExtras, 2, 70.0f, 35.0f, 160.0f, 0.1f) { Parent = fov }; @@ -598,7 +601,7 @@ namespace FlaxEditor.Viewport { var orthoSize = ViewWidgetButtonMenu.AddButton("Ortho Scale"); orthoSize.CloseMenuOnClick = false; - var orthoSizeValue = new FloatValueBox(_orthoSize, 90, 2, 70.0f, 0.001f, 100000.0f, 0.01f) + var orthoSizeValue = new FloatValueBox(_orthoSize, xLocationForExtras, 2, 70.0f, 0.001f, 100000.0f, 0.01f) { Parent = orthoSize }; @@ -615,7 +618,7 @@ namespace FlaxEditor.Viewport { var nearPlane = ViewWidgetButtonMenu.AddButton("Near Plane"); nearPlane.CloseMenuOnClick = false; - var nearPlaneValue = new FloatValueBox(2.0f, 90, 2, 70.0f, 0.001f, 1000.0f) + var nearPlaneValue = new FloatValueBox(2.0f, xLocationForExtras, 2, 70.0f, 0.001f, 1000.0f) { Parent = nearPlane }; @@ -627,7 +630,7 @@ namespace FlaxEditor.Viewport { var farPlane = ViewWidgetButtonMenu.AddButton("Far Plane"); farPlane.CloseMenuOnClick = false; - var farPlaneValue = new FloatValueBox(1000, 90, 2, 70.0f, 10.0f) + var farPlaneValue = new FloatValueBox(1000, xLocationForExtras, 2, 70.0f, 10.0f) { Parent = farPlane }; @@ -639,7 +642,7 @@ namespace FlaxEditor.Viewport { var brightness = ViewWidgetButtonMenu.AddButton("Brightness"); brightness.CloseMenuOnClick = false; - var brightnessValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.001f, 10.0f, 0.001f) + var brightnessValue = new FloatValueBox(1.0f, xLocationForExtras, 2, 70.0f, 0.001f, 10.0f, 0.001f) { Parent = brightness }; @@ -651,7 +654,7 @@ namespace FlaxEditor.Viewport { var resolution = ViewWidgetButtonMenu.AddButton("Resolution"); resolution.CloseMenuOnClick = false; - var resolutionValue = new FloatValueBox(1.0f, 90, 2, 70.0f, 0.1f, 4.0f, 0.001f) + var resolutionValue = new FloatValueBox(1.0f, xLocationForExtras, 2, 70.0f, 0.1f, 4.0f, 0.001f) { Parent = resolution }; @@ -663,7 +666,7 @@ namespace FlaxEditor.Viewport { var invert = ViewWidgetButtonMenu.AddButton("Invert Panning"); invert.CloseMenuOnClick = false; - var invertValue = new CheckBox(90, 2, _invertPanning) + var invertValue = new CheckBox(xLocationForExtras, 2, _invertPanning) { Parent = invert }; diff --git a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs index fc7fcdbe1..c6ce5a7b5 100644 --- a/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs +++ b/Source/Editor/Viewport/Previews/ParticleSystemPreview.cs @@ -68,7 +68,7 @@ namespace FlaxEditor.Viewport.Previews /// public bool ShowBounds { - get => _boundsModel?.IsActive ?? false; + get => _boundsModel != null ? _boundsModel.IsActive : false; set { if (value == ShowBounds) @@ -110,7 +110,7 @@ namespace FlaxEditor.Viewport.Previews /// public bool ShowOrigin { - get => _originModel?.IsActive ?? false; + get => _originModel != null ? _originModel.IsActive : false; set { if (value == ShowOrigin) diff --git a/Source/Editor/Viewport/Previews/TexturePreview.cs b/Source/Editor/Viewport/Previews/TexturePreview.cs index a33a61f86..ec10bb019 100644 --- a/Source/Editor/Viewport/Previews/TexturePreview.cs +++ b/Source/Editor/Viewport/Previews/TexturePreview.cs @@ -500,7 +500,7 @@ namespace FlaxEditor.Viewport.Previews /// protected override void CalculateTextureRect(out Rectangle rect) { - CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect); + CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect); } /// @@ -549,7 +549,7 @@ namespace FlaxEditor.Viewport.Previews /// protected override void CalculateTextureRect(out Rectangle rect) { - CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect); + CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect); } /// @@ -604,7 +604,7 @@ namespace FlaxEditor.Viewport.Previews /// protected override void CalculateTextureRect(out Rectangle rect) { - CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect); + CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect); } /// @@ -659,7 +659,7 @@ namespace FlaxEditor.Viewport.Previews /// protected override void CalculateTextureRect(out Rectangle rect) { - CalculateTextureRect(_asset?.Size ?? new Float2(100), Size, out rect); + CalculateTextureRect(_asset != null ? _asset.Size : new Float2(100), Size, out rect); } /// diff --git a/Source/Editor/Windows/AboutDialog.cs b/Source/Editor/Windows/AboutDialog.cs index 4b9595445..b059dadcb 100644 --- a/Source/Editor/Windows/AboutDialog.cs +++ b/Source/Editor/Windows/AboutDialog.cs @@ -52,9 +52,11 @@ namespace FlaxEditor.Windows VerticalAlignment = TextAlignment.Near, Parent = this }; - var copyVersionButton = new Button(Width - 104, 6, 100, 20) + var buttonText = "Copy version info"; + var fontSize = Style.Current.FontMedium.MeasureText(buttonText); + var copyVersionButton = new Button(Width - fontSize.X - 8, 6, fontSize.X + 4, 20) { - Text = "Copy version info", + Text = buttonText, TooltipText = "Copies the current engine version information to system clipboard.", Parent = this }; diff --git a/Source/Editor/Windows/Assets/CollisionDataWindow.cs b/Source/Editor/Windows/Assets/CollisionDataWindow.cs index cc1daa45b..1b6ed914c 100644 --- a/Source/Editor/Windows/Assets/CollisionDataWindow.cs +++ b/Source/Editor/Windows/Assets/CollisionDataWindow.cs @@ -200,6 +200,7 @@ namespace FlaxEditor.Windows.Assets ViewportCamera = new FPSCamera(), Parent = _split.Panel1 }; + _preview.Task.ViewFlags &= ~ViewFlags.Sky & ~ViewFlags.Bloom; // Asset properties _propertiesPresenter = new CustomEditorPresenter(null); diff --git a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs index d5ab2ae8a..5f1273999 100644 --- a/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs +++ b/Source/Editor/Windows/Assets/MaterialInstanceWindow.cs @@ -69,7 +69,7 @@ namespace FlaxEditor.Windows.Assets [EditorDisplay("General"), Tooltip("The base material used to override it's properties")] public MaterialBase BaseMaterial { - get => Window?.Asset?.BaseMaterial; + get => Window?.Asset != null ? Window?.Asset.BaseMaterial : null; set { var asset = Window?.Asset; @@ -101,10 +101,12 @@ namespace FlaxEditor.Windows.Assets [HideInEditor] public object[] Values { - get => Window?.Asset?.Parameters.Select(x => x.Value).ToArray(); + get => Window?.Asset != null ? Window?.Asset.Parameters.Select(x => x.Value).ToArray() : null; set { - var parameters = Window?.Asset?.Parameters; + if (Window?.Asset == null) + return; + var parameters = Window?.Asset.Parameters; if (value != null && parameters != null) { if (value.Length != parameters.Length) @@ -131,9 +133,11 @@ namespace FlaxEditor.Windows.Assets [HideInEditor] public FlaxEngine.Object[] ValuesRef { - get => Window?.Asset?.Parameters.Select(x => x.Value as FlaxEngine.Object).ToArray(); + get => Window?.Asset != null ? Window?.Asset.Parameters.Select(x => x.Value as FlaxEngine.Object).ToArray() : null; set { + if (Window?.Asset == null) + return; var parameters = Window?.Asset?.Parameters; if (value != null && parameters != null) { @@ -293,7 +297,7 @@ namespace FlaxEditor.Windows.Assets var p = (MaterialParameter)e.Tag; // Try to get default value (from the base material) - var pBase = baseMaterial?.GetParameter(p.Name); + var pBase = baseMaterial != null ? baseMaterial.GetParameter(p.Name) : null; if (pBase != null && pBase.ParameterType == p.ParameterType) { valueContainer.SetDefaultValue(pBase.Value); diff --git a/Source/Editor/Windows/Assets/ModelWindow.cs b/Source/Editor/Windows/Assets/ModelWindow.cs index f70f6a3b5..c2764a5a6 100644 --- a/Source/Editor/Windows/Assets/ModelWindow.cs +++ b/Source/Editor/Windows/Assets/ModelWindow.cs @@ -134,7 +134,7 @@ namespace FlaxEditor.Windows.Assets if (Window._skipEffectsGuiEvents) return; - Window._isolateIndex = mesh?.MaterialSlotIndex ?? -1; + Window._isolateIndex = mesh != null ? mesh.MaterialSlotIndex : -1; Window.UpdateEffectsOnAsset(); UpdateEffectsOnUI(); } @@ -144,7 +144,7 @@ namespace FlaxEditor.Windows.Assets if (Window._skipEffectsGuiEvents) return; - Window._highlightIndex = mesh?.MaterialSlotIndex ?? -1; + Window._highlightIndex = mesh != null ? mesh.MaterialSlotIndex : -1; Window.UpdateEffectsOnAsset(); UpdateEffectsOnUI(); } @@ -326,7 +326,7 @@ namespace FlaxEditor.Windows.Assets [EditorOrder(10), EditorDisplay("Materials", EditorDisplayAttribute.InlineStyle)] public MaterialSlot[] MaterialSlots { - get => Asset?.MaterialSlots; + get => Asset != null ? Asset.MaterialSlots : null; set { if (Asset != null) diff --git a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs index 328369680..17eda1358 100644 --- a/Source/Editor/Windows/Assets/ParticleSystemWindow.cs +++ b/Source/Editor/Windows/Assets/ParticleSystemWindow.cs @@ -187,7 +187,7 @@ namespace FlaxEditor.Windows.Assets base.Initialize(layout); var emitterTrack = Values[0] as EmitterTrackProxy; - if (emitterTrack?._effect?.Parameters == null) + if (emitterTrack?._effect == null || emitterTrack?._effect.Parameters == null) return; var group = layout.Group("Parameters"); diff --git a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs index 824928743..162944144 100644 --- a/Source/Editor/Windows/Assets/SceneAnimationWindow.cs +++ b/Source/Editor/Windows/Assets/SceneAnimationWindow.cs @@ -792,7 +792,7 @@ namespace FlaxEditor.Windows.Assets { if (_previewButton.Checked) return; - _previewPlayerPicker.Value = _timeline.Player; + _previewPlayerPicker.Value = _timeline.Player != null ? _timeline.Player : null; _cachedPlayerId = _timeline.Player?.ID ?? Guid.Empty; } @@ -821,7 +821,7 @@ namespace FlaxEditor.Windows.Assets if (_timeline.IsModified) { var time = _timeline.CurrentTime; - var isPlaying = _previewPlayer?.IsPlaying ?? false; + var isPlaying = _previewPlayer != null ? _previewPlayer.IsPlaying : false; _timeline.Save(_asset); if (_previewButton.Checked && _previewPlayer != null) { diff --git a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs index a7ee6e767..d360e5570 100644 --- a/Source/Editor/Windows/Assets/SkinnedModelWindow.cs +++ b/Source/Editor/Windows/Assets/SkinnedModelWindow.cs @@ -151,7 +151,7 @@ namespace FlaxEditor.Windows.Assets if (Window._skipEffectsGuiEvents) return; - Window._isolateIndex = mesh?.MaterialSlotIndex ?? -1; + Window._isolateIndex = mesh != null ? mesh.MaterialSlotIndex : -1; Window.UpdateEffectsOnAsset(); UpdateEffectsOnUI(); } @@ -165,7 +165,7 @@ namespace FlaxEditor.Windows.Assets if (Window._skipEffectsGuiEvents) return; - Window._highlightIndex = mesh?.MaterialSlotIndex ?? -1; + Window._highlightIndex = mesh != null ? mesh.MaterialSlotIndex : -1; Window.UpdateEffectsOnAsset(); UpdateEffectsOnUI(); } @@ -415,7 +415,7 @@ namespace FlaxEditor.Windows.Assets [EditorOrder(10), EditorDisplay("Materials", EditorDisplayAttribute.InlineStyle)] public MaterialSlot[] MaterialSlots { - get => Asset?.MaterialSlots; + get => Asset != null ? Asset.MaterialSlots : null; set { if (Asset != null) diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index 4ea31b35e..1d188a32c 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -160,7 +160,7 @@ namespace FlaxEditor.Windows Parent = this, }; _viewDropdown.Clicked += OnViewButtonClicked; - _searchBox = new SearchBox(false, _viewDropdown.Right + 2, 2, Width - _viewDropdown.Right - 2 - _scrollSize) + _searchBox = new SearchBox(false, _viewDropdown.Right + 2, 2, Width - _viewDropdown.Right - 4) { Parent = this, }; @@ -171,11 +171,12 @@ namespace FlaxEditor.Windows Maximum = 0, }; _hScroll.ValueChanged += OnHScrollValueChanged; - _vScroll = new VScrollBar(this, Width - _scrollSize, Height, _scrollSize) + _vScroll = new VScrollBar(this, Width - _scrollSize, Height - _viewDropdown.Height - 2, _scrollSize) { ThumbThickness = 10, Maximum = 0, }; + _vScroll.Y += _viewDropdown.Height + 2; _vScroll.ValueChanged += OnVScrollValueChanged; _output = new OutputTextBox { @@ -409,7 +410,7 @@ namespace FlaxEditor.Windows if (_output != null) { - _searchBox.Width = Width - _viewDropdown.Right - 2 - _scrollSize; + _searchBox.Width = Width - _viewDropdown.Right - 4; _output.Size = new Float2(_vScroll.X - 2, _hScroll.Y - 4 - _viewDropdown.Bottom); } } diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 609f98f83..fba052269 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -173,6 +173,9 @@ namespace FlaxEditor.Windows // Spawn it Editor.SceneEditing.Spawn(actor, parentActor); + + Editor.SceneEditing.Select(actor); + Rename(); } /// diff --git a/Source/Editor/Windows/SplashScreen.cpp b/Source/Editor/Windows/SplashScreen.cpp index 7cf7a7f78..d2371a540 100644 --- a/Source/Editor/Windows/SplashScreen.cpp +++ b/Source/Editor/Windows/SplashScreen.cpp @@ -18,21 +18,21 @@ const Char* SplashScreenQuotes[] = TEXT("Loading"), TEXT("Unloading"), TEXT("Reloading"), - TEXT("Reloading gun"), + TEXT("Downloading more RAM"), TEXT("Consuming your RAM"), TEXT("Burning your CPU"), - TEXT("#BetterThanUnity"), TEXT("Rendering buttons"), TEXT("Collecting crash data"), - TEXT("Downloading porn"), #if PLATFORM_WINDOWS - TEXT("Removing 'C:\\Windows\\'"), + TEXT("We're getting everything ready for you."), #elif PLATFORM_LINUX - TEXT("Time to switch to Windows?"), - TEXT("Installing Windows 10"), + TEXT("Try it on a Raspberry"), + TEXT("Trying to exit vim"), + TEXT("Sudo flax --loadproject"), #elif PLATFORM_MAC - TEXT("Hacking your iPhone"), + TEXT("don't compare Macbooks to oranges."), TEXT("Why does macbook heat up?\nBecause it doesn't have windows"), + TEXT("Starting Direc... um, Vulkan renderer."), #endif TEXT("Kappa!"), TEXT("How you doin'?"), @@ -40,12 +40,10 @@ const Char* SplashScreenQuotes[] = TEXT("Bond. James Bond."), TEXT("To infinity and beyond!"), TEXT("Houston, we have a problem"), - TEXT("NotImplementedEngineException"), TEXT("Made in Poland"), TEXT("We like you"), TEXT("Compiling the compiler"), TEXT("Flax it up!"), - TEXT("Fun fact: Fortnite runs on Flax"), TEXT("Toss a coin to your Witcher!!!"), TEXT("Holy Moly!"), TEXT("Just Read the Instructions"), @@ -60,7 +58,6 @@ const Char* SplashScreenQuotes[] = TEXT("They see me loadin'"), TEXT("Loadin' loadin' and loadin' loadin'"), TEXT("Procedurally generating buttons"), - TEXT("Out of Memory Exception!"), TEXT("Running Big Bang simulation"), TEXT("Calculating infinity"), TEXT("Dividing infinity by zero"), @@ -70,10 +67,7 @@ const Char* SplashScreenQuotes[] = TEXT("Whatever you do, do it well.\n~Walt Disney"), TEXT("Here's Johnny!"), TEXT("Did you see that? No... I don't think so"), - TEXT("Collecting unreal power"), TEXT("Stay safe, friend"), - TEXT("trolololololololololololo"), - TEXT("xD"), TEXT("Come to the dark side"), TEXT("Flax Facts: This is a loading screen"), TEXT("Don't Stop Me Now"), @@ -81,61 +75,58 @@ const Char* SplashScreenQuotes[] = TEXT("Made with Flax"), TEXT("This is the way"), TEXT("The quick brown fox jumps over the lazy dog"), - TEXT("Hit The Road Jack"), TEXT("You have 7 lives left"), TEXT("May the Force be with you"), TEXT("A martini. Shaken, not stirred"), TEXT("Hasta la vista, baby"), TEXT("Winter is coming"), - TEXT("You know nothing, Jon Snow"), TEXT("Create something awesome!"), TEXT("Well Polished Engine"), TEXT("Error 404: Joke Not Found"), TEXT("Rushing B"), TEXT("Putting pineapple on pizza"), - TEXT("Loading Simulation"), + TEXT("Entering the Matrix"), TEXT("Get ready for a surprise!"), TEXT("Coffee is my fuel"), - TEXT("Installing a free copy of Cyberpunk 2077"), TEXT("With great power comes great electricity bill"), TEXT("Flax was made in the same city as Witcher 3"), TEXT("So JavaScript is a scripting version of Java"), TEXT("Good things take time.\n~Someone"), - TEXT("Get shit done"), TEXT("Hold Tight! Loading Flax"), TEXT("That's one small step for a man,\none giant leap for mankind"), TEXT("Remember to save your work frequently"), TEXT("In case of fire:\ngit commit, git push, leave building"), TEXT("Keep calm and make games"), TEXT("You're breathtaking!!!"), - TEXT("Do regular dogs see police dogs & think,\nOh no it's a cop?"), - TEXT("Dear Santa,\nDefine naughty."), TEXT("Blah, blah"), TEXT("My PRECIOUS!!!!"), TEXT("YOU SHALL NOT PASS!"), TEXT("You have my bow.\nAnd my axe!"), TEXT("To the bridge of Khazad-dum."), TEXT("One ring to rule them all.\nOne ring to find them."), - TEXT("Ladies and gentelman, we got him"), - TEXT("Cyberpunk of game engines"), TEXT("That's what she said"), - TEXT("Compiling Shaders (93,788)"), + TEXT("We could be compiling shaders here"), TEXT("Hello There"), TEXT("BAGUETTE"), - TEXT("All we had to do was follow the damn train, CJ"), TEXT("Here we go again"), TEXT("@everyone"), TEXT("Potato"), TEXT("Python is a programming snek"), TEXT("Flax will start when pigs will fly"), - TEXT("I'm the android sent by CyberLife"), - TEXT("Fancy-ass ray tracing, rtx on, lighting"), TEXT("ZOINKS"), TEXT("Scooby dooby doo"), TEXT("You shall not load!"), TEXT("The roof, the roof, the roof is on fire!"), - TEXT("I've seen better documentation...\nFrom ransomware gangs!"), TEXT("Slava Ukraini!"), + TEXT("RTX off... for now!"), + TEXT("Increasing Fiber count"), + TEXT("Now this is podracing!"), + TEXT("Weird flax, but ok"), + TEXT("Reticulating Splines"), + TEXT("Discombobulating"), + TEXT("Who is signing all these integers?!"), + TEXT("Flax fact: Flax was called Celelej once."), + TEXT("Changing text overflow setti-"), }; SplashScreen::~SplashScreen() diff --git a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp index fa7999ce0..8fef8e6d3 100644 --- a/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp +++ b/Source/Engine/Animations/SceneAnimations/SceneAnimationPlayer.cpp @@ -905,7 +905,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3 MException ex(exception); ex.Log(LogType::Error, TEXT("Property")); } - else if (!MCore::Type::IsPointer(valueType)) + else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType)) { if (boxed) Platform::MemoryCopy(value, MCore::Object::Unbox(boxed), valueSize); diff --git a/Source/Engine/Core/Math/Vector2.cs b/Source/Engine/Core/Math/Vector2.cs index 2af365638..568c51764 100644 --- a/Source/Engine/Core/Math/Vector2.cs +++ b/Source/Engine/Core/Math/Vector2.cs @@ -58,6 +58,7 @@ using Mathr = FlaxEngine.Mathf; */ using System; using System.Globalization; +using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -953,6 +954,91 @@ namespace FlaxEngine return result; } + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + /// Defines the upper limit on the speed of the Smooth Damp. + public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime, float maxSpeed) + { + return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, Time.DeltaTime); + } + + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime) + { + return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime); + } + + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + /// Defines the upper limit on the speed of the Smooth Damp. + /// Delta Time, represents the time elapsed since last frame. + public static Vector2 SmoothDamp(Vector2 current, Vector2 target, ref Vector2 currentVelocity, float smoothTime, [DefaultValue("float.PositiveInfinity")] float maxSpeed, [DefaultValue("Time.DeltaTime")] float deltaTime) + { + smoothTime = Mathf.Max(0.0001f, smoothTime); + Real a = 2f / smoothTime; + Real b = a * deltaTime; + Real e = 1f / (1f + b + 0.48f * b * b + 0.235f * b * b * b); + + Real change_x = current.X - target.X; + Real change_y = current.Y - target.Y; + Vector2 originalTo = target; + + Real maxChangeSpeed = maxSpeed * smoothTime; + Real changeSq = maxChangeSpeed * maxChangeSpeed; + Real sqrDist = change_x * change_x + change_y * change_y; + if (sqrDist > changeSq) + { + var dist = (Real)Math.Sqrt(sqrDist); + change_x = change_x / dist * maxChangeSpeed; + change_y = change_y / dist * maxChangeSpeed; + } + + target.X = current.X - change_x; + target.Y = current.Y - change_y; + + Real temp_x = (currentVelocity.X + a * change_x) * deltaTime; + Real temp_y = (currentVelocity.Y + a * change_y) * deltaTime; + + currentVelocity.X = (currentVelocity.X - a * temp_x) * e; + currentVelocity.Y = (currentVelocity.Y - a * temp_y) * e; + + Real output_x = target.X + (change_x + temp_x) * e; + Real output_y = target.Y + (change_y + temp_y) * e; + + Real x1 = originalTo.X - current.X; + Real y1 = originalTo.Y - current.Y; + + Real x2 = output_x - originalTo.X; + Real y2 = output_y - originalTo.Y; + + if (x1 * x2 + y1 * y2 > 0) + { + output_x = originalTo.X; + output_y = originalTo.Y; + + currentVelocity.X = (output_x - originalTo.X) / deltaTime; + currentVelocity.Y = (output_y - originalTo.Y) / deltaTime; + } + + return new Vector2(output_x, output_y); + } + /// /// Performs a cubic interpolation between two vectors. /// diff --git a/Source/Engine/Core/Math/Vector3.cs b/Source/Engine/Core/Math/Vector3.cs index 72f538269..280093619 100644 --- a/Source/Engine/Core/Math/Vector3.cs +++ b/Source/Engine/Core/Math/Vector3.cs @@ -58,6 +58,7 @@ using Mathr = FlaxEngine.Mathf; */ using System; using System.Globalization; +using System.ComponentModel; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1042,6 +1043,103 @@ namespace FlaxEngine return result; } + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + /// Defines the upper limit on the speed of the Smooth Damp. + public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed) + { + return SmoothDamp(current, target, ref currentVelocity, smoothTime, maxSpeed, Time.DeltaTime); + } + + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime) + { + return SmoothDamp(current, target, ref currentVelocity, smoothTime, float.PositiveInfinity, Time.DeltaTime); + } + + /// + /// Performs a gradual change of a vector towards a specified target over time + /// + /// Current vector. + /// Target vector. + /// Used to store the current velocity. + /// Determines the approximate time it should take to reach the target vector. + /// Defines the upper limit on the speed of the Smooth Damp. + /// Delta Time, represents the time elapsed since last frame. + public static Vector3 SmoothDamp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, [DefaultValue("float.PositiveInfinity")] float maxSpeed, [DefaultValue("Time.DeltaTime")] float deltaTime) + { + smoothTime = Mathf.Max(0.0001f, smoothTime); + Real a = 2f / smoothTime; + Real b = a * deltaTime; + Real e = 1f / (1f + b + 0.48f * b * b + 0.235f * b * b * b); + + Real change_x = current.X - target.X; + Real change_y = current.Y - target.Y; + Real change_z = current.Z - target.Z; + + Vector3 originalTo = target; + + Real maxChangeSpeed = maxSpeed * smoothTime; + Real changeSq = maxChangeSpeed * maxChangeSpeed; + Real sqrLen = change_x * change_x + change_y * change_y + change_z * change_z; + if (sqrLen > changeSq) + { + var len = (Real)Math.Sqrt(sqrLen); + change_x = change_x / len * maxChangeSpeed; + change_y = change_y / len * maxChangeSpeed; + change_z = change_z / len * maxChangeSpeed; + } + + target.X = current.X - change_x; + target.Y = current.Y - change_y; + target.Z = current.Z - change_z; + + Real temp_x = (currentVelocity.X + a * change_x) * deltaTime; + Real temp_y = (currentVelocity.Y + a * change_y) * deltaTime; + Real temp_z = (currentVelocity.Z + a * change_z) * deltaTime; + + currentVelocity.X = (currentVelocity.X - a * temp_x) * e; + currentVelocity.Y = (currentVelocity.Y - a * temp_y) * e; + currentVelocity.Z = (currentVelocity.Z - a * temp_z) * e; + + Real output_x = target.X + (change_x + temp_x) * e; + Real output_y = target.Y + (change_y + temp_y) * e; + Real output_z = target.Z + (change_z + temp_z) * e; + + Real x1 = originalTo.X - current.X; + Real y1 = originalTo.Y - current.Y; + Real z1 = originalTo.Z - current.Z; + + Real x2 = output_x - originalTo.X; + Real y2 = output_y - originalTo.Y; + Real z2 = output_z - originalTo.Z; + + if (x1 * x2 + y1 * y2 + z1 * z2 > 0) + { + output_x = originalTo.X; + output_y = originalTo.Y; + output_z = originalTo.Z; + + currentVelocity.X = (output_x - originalTo.X) / deltaTime; + currentVelocity.Y = (output_y - originalTo.Y) / deltaTime; + currentVelocity.Z = (output_z - originalTo.Z) / deltaTime; + } + + return new Vector3(output_x, output_y, output_z); + } + + /// /// Performs a cubic interpolation between two vectors. /// diff --git a/Source/Engine/Engine/NativeInterop.Unmanaged.cs b/Source/Engine/Engine/NativeInterop.Unmanaged.cs index 9cc5a1f1c..b40fa740a 100644 --- a/Source/Engine/Engine/NativeInterop.Unmanaged.cs +++ b/Source/Engine/Engine/NativeInterop.Unmanaged.cs @@ -1230,7 +1230,7 @@ namespace FlaxEngine.Interop internal static bool GetTypeIsReference(ManagedHandle typeHandle) { Type type = Unsafe.As(typeHandle.Target); - return type.IsByRef; + return !type.IsValueType; // Maybe also type.IsByRef? } [UnmanagedCallersOnly] diff --git a/Source/Engine/Engine/Screen.cpp b/Source/Engine/Engine/Screen.cpp index 2bc6e1f58..fc7e8a022 100644 --- a/Source/Engine/Engine/Screen.cpp +++ b/Source/Engine/Engine/Screen.cpp @@ -181,6 +181,11 @@ void Screen::SetGameWindowMode(GameWindowMode windowMode) #endif } +Window* Screen::GetMainWindow() +{ + return Engine::MainWindow; +} + void ScreenService::Update() { #if USE_EDITOR diff --git a/Source/Engine/Engine/Screen.h b/Source/Engine/Engine/Screen.h index 42be20a38..b7bd89c38 100644 --- a/Source/Engine/Engine/Screen.h +++ b/Source/Engine/Engine/Screen.h @@ -96,4 +96,10 @@ DECLARE_SCRIPTING_TYPE_NO_SPAWN(Screen); /// /// The window mode. API_PROPERTY() static void SetGameWindowMode(GameWindowMode windowMode); + + /// + /// Gets the main window. + /// + /// The current window. Will be null if fails. + API_PROPERTY() static Window* GetMainWindow(); }; diff --git a/Source/Engine/Level/Actor.cs b/Source/Engine/Level/Actor.cs index 661b350cb..dbe8a89b5 100644 --- a/Source/Engine/Level/Actor.cs +++ b/Source/Engine/Level/Actor.cs @@ -364,13 +364,20 @@ namespace FlaxEngine /// The point (world-space). /// The axis (normalized). /// The angle (in degrees). - public void RotateAround(Vector3 point, Vector3 axis, float angle) + /// /// Whether to orient the actor the same amount as rotation. + public void RotateAround(Vector3 point, Vector3 axis, float angle, bool orientActor = true) { var transform = Transform; var q = Quaternion.RotationAxis(axis, angle * Mathf.DegreesToRadians); - var dif = (transform.Translation - point) * q; - transform.Translation = point + dif; - transform.Orientation = q; + if (Vector3.NearEqual(point, transform.Translation) && orientActor) + transform.Orientation *= q; + else + { + var dif = (transform.Translation - point) * q; + transform.Translation = point + dif; + if (orientActor) + transform.Orientation *= q; + } Transform = transform; } diff --git a/Source/Engine/Profiler/ProfilerCPU.cpp b/Source/Engine/Profiler/ProfilerCPU.cpp index 26f9e49c2..7b9e2c6e3 100644 --- a/Source/Engine/Profiler/ProfilerCPU.cpp +++ b/Source/Engine/Profiler/ProfilerCPU.cpp @@ -129,8 +129,15 @@ void ProfilerCPU::Thread::EndEvent() { const double time = Platform::GetTimeSeconds() * 1000.0; _depth--; - Event& e = (Buffer.Last()--).Event(); - e.End = time; + for (auto i = Buffer.Last(); i != Buffer.Begin(); --i) + { + Event& e = i.Event(); + if (e.End <= 0) + { + e.End = time; + break; + } + } } bool ProfilerCPU::IsProfilingCurrentThread() diff --git a/Source/Engine/Profiler/ProfilerCPU.h b/Source/Engine/Profiler/ProfilerCPU.h index 124082c9b..ccfeb8ac4 100644 --- a/Source/Engine/Profiler/ProfilerCPU.h +++ b/Source/Engine/Profiler/ProfilerCPU.h @@ -121,15 +121,39 @@ public: EventBuffer* _buffer; int32 _index; - Iterator(EventBuffer* buffer, const int32 index) + FORCE_INLINE Iterator(EventBuffer* buffer, const int32 index) : _buffer(buffer) , _index(index) { } - Iterator(const Iterator& i) = default; - public: + FORCE_INLINE Iterator(const Iterator& other) + : _buffer(other._buffer) + , _index(other._index) + { + } + + FORCE_INLINE Iterator(Iterator&& other) noexcept + : _buffer(other._buffer) + , _index(other._index) + { + } + + FORCE_INLINE Iterator& operator=(Iterator&& other) + { + _buffer = other._buffer; + _index = other._index; + return *this; + } + + FORCE_INLINE Iterator& operator=(const Iterator& other) + { + _buffer = other._buffer; + _index = other._index; + return *this; + } + FORCE_INLINE int32 Index() const { return _index; @@ -141,15 +165,13 @@ public: return _buffer->Get(_index); } - bool IsEnd() const + FORCE_INLINE bool IsEnd() const { - ASSERT_LOW_LAYER(_buffer); return _index == _buffer->_head; } - bool IsNotEnd() const + FORCE_INLINE bool IsNotEnd() const { - ASSERT_LOW_LAYER(_buffer); return _index != _buffer->_head; } @@ -164,31 +186,27 @@ public: } public: - Iterator& operator++() + FORCE_INLINE Iterator& operator++() { - ASSERT(_buffer); _index = (_index + 1) & _buffer->_capacityMask; return *this; } - Iterator operator++(int) + FORCE_INLINE Iterator operator++(int) { - ASSERT(_buffer); Iterator temp = *this; _index = (_index + 1) & _buffer->_capacityMask; return temp; } - Iterator& operator--() + FORCE_INLINE Iterator& operator--() { - ASSERT(_buffer); _index = (_index - 1) & _buffer->_capacityMask; return *this; } - Iterator operator--(int) + FORCE_INLINE Iterator operator--(int) { - ASSERT(_buffer); Iterator temp = *this; _index = (_index - 1) & _buffer->_capacityMask; return temp; diff --git a/Source/Engine/Scripting/BinaryModule.cpp b/Source/Engine/Scripting/BinaryModule.cpp index 2f9a42bbc..efd147917 100644 --- a/Source/Engine/Scripting/BinaryModule.cpp +++ b/Source/Engine/Scripting/BinaryModule.cpp @@ -1240,8 +1240,12 @@ bool ManagedBinaryModule::InvokeMethod(void* method, const Variant& instance, Sp return true; } +#if USE_NETCORE + mInstance = instanceObject; +#else // For value-types instance is the actual boxed object data, not te object itself mInstance = instanceObjectClass->IsValueType() ? MCore::Object::Unbox(instanceObject) : instanceObject; +#endif } // Marshal parameters diff --git a/Source/Engine/Scripting/Scripting.cpp b/Source/Engine/Scripting/Scripting.cpp index 34cc83054..cce66cd98 100644 --- a/Source/Engine/Scripting/Scripting.cpp +++ b/Source/Engine/Scripting/Scripting.cpp @@ -104,7 +104,7 @@ namespace MMethod* _method_LateFixedUpdate = nullptr; MMethod* _method_Draw = nullptr; MMethod* _method_Exit = nullptr; - Array> _nonNativeModules; + Dictionary> _nonNativeModules; #if USE_EDITOR bool LastBinariesLoadTriggeredCompilation = false; #endif @@ -329,6 +329,8 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde // Check if that module has been already registered BinaryModule* module = BinaryModule::GetModule(nameAnsi); + if (!module) + _nonNativeModules.TryGet(nameAnsi, module); if (!module) { // C++ @@ -398,7 +400,7 @@ bool Scripting::LoadBinaryModules(const String& path, const String& projectFolde { // Create module if native library is not used module = New(nameAnsi); - _nonNativeModules.Add(module); + _nonNativeModules.Add(nameAnsi, module); } } diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index 3e11b3e14..8347fe7f8 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -282,6 +282,12 @@ namespace FlaxEngine TextBoxBackgroundSelected = Color.FromBgra(0xFF3F3F46), CollectionBackgroundColor = Color.FromBgra(0x14CCCCCC), SharedTooltip = new Tooltip(), + Statusbar = new Style.StatusbarStyle() + { + PlayMode = Color.FromBgra(0xFF2F9135), + Failed = Color.FromBgra(0xFF9C2424), + Loading = Color.FromBgra(0xFF2D2D30) + } }; style.DragWindow = style.BackgroundSelected * 0.7f; diff --git a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs index 9ad9db1d3..d3469670a 100644 --- a/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/GPUTextureBrush.cs @@ -37,7 +37,7 @@ namespace FlaxEngine.GUI } /// - public Float2 Size => Texture?.Size ?? Float2.Zero; + public Float2 Size => Texture != null ? Texture.Size : Float2.Zero; /// public void Draw(Rectangle rect, Color color) diff --git a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs index d49e5519b..755f7527b 100644 --- a/Source/Engine/UI/GUI/Brushes/TextureBrush.cs +++ b/Source/Engine/UI/GUI/Brushes/TextureBrush.cs @@ -104,7 +104,7 @@ namespace FlaxEngine.GUI } /// - public Float2 Size => Texture?.Size ?? Float2.Zero; + public Float2 Size => Texture != null ? Texture.Size : Float2.Zero; /// public unsafe void Draw(Rectangle rect, Color color) diff --git a/Source/Engine/UI/GUI/Common/Label.cs b/Source/Engine/UI/GUI/Common/Label.cs index 9aaaeed26..3c7c04fb2 100644 --- a/Source/Engine/UI/GUI/Common/Label.cs +++ b/Source/Engine/UI/GUI/Common/Label.cs @@ -74,10 +74,16 @@ namespace FlaxEngine.GUI [EditorDisplay("Text Style"), EditorOrder(2022), Tooltip("The text wrapping within the control bounds.")] public TextWrapping Wrapping { get; set; } = TextWrapping.NoWrap; + /// + /// Gets or sets the text wrapping within the control bounds. + /// + [EditorDisplay("Text Style"), EditorOrder(2023), Tooltip("The gap between lines when wrapping and more than a single line is displayed."), Limit(0f)] + public float BaseLinesGapScale { get; set; } = 1.0f; + /// /// Gets or sets the font. /// - [EditorDisplay("Text Style"), EditorOrder(2023)] + [EditorDisplay("Text Style"), EditorOrder(2024)] public FontReference Font { get => _font; @@ -99,7 +105,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the custom material used to render the text. It must has domain set to GUI and have a public texture parameter named Font used to sample font atlas texture with font characters data. /// - [EditorDisplay("Text Style"), EditorOrder(2024)] + [EditorDisplay("Text Style"), EditorOrder(2025)] public MaterialBase Material { get; set; } /// @@ -227,7 +233,7 @@ namespace FlaxEngine.GUI } } - Render2D.DrawText(_font.GetFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, 1.0f, scale); + Render2D.DrawText(_font.GetFont(), Material, _text, rect, color, hAlignment, wAlignment, Wrapping, BaseLinesGapScale, scale); if (ClipText) Render2D.PopClip(); @@ -249,6 +255,7 @@ namespace FlaxEngine.GUI else if (_autoWidth && !_autoHeight) layout.Bounds.Size.Y = Height - Margin.Height; _textSize = font.MeasureText(_text, ref layout); + _textSize.Y *= BaseLinesGapScale; // Check if size is controlled via text if (_autoWidth || _autoHeight) diff --git a/Source/Engine/UI/GUI/Panels/BlurPanel.cs b/Source/Engine/UI/GUI/Panels/BlurPanel.cs index 0fe506e44..055535aa8 100644 --- a/Source/Engine/UI/GUI/Panels/BlurPanel.cs +++ b/Source/Engine/UI/GUI/Panels/BlurPanel.cs @@ -11,7 +11,7 @@ namespace FlaxEngine.GUI /// /// Gets or sets the blur strength. Defines how blurry the background is. Larger numbers increase blur, resulting in a larger runtime cost on the GPU. /// - [EditorOrder(0), Limit(0, 100, 0.0f)] + [EditorOrder(0), Limit(0, 100, 0.1f)] public float BlurStrength { get; set; } /// @@ -29,10 +29,9 @@ namespace FlaxEngine.GUI } /// - public override void Draw() + public override void DrawSelf() { - base.Draw(); - + base.DrawSelf(); var size = Size; var strength = BlurStrength; if (BlurScaleWithSize) diff --git a/Source/Engine/UI/GUI/Style.cs b/Source/Engine/UI/GUI/Style.cs index fac65e22f..8f34a703c 100644 --- a/Source/Engine/UI/GUI/Style.cs +++ b/Source/Engine/UI/GUI/Style.cs @@ -164,6 +164,12 @@ namespace FlaxEngine.GUI [EditorOrder(200)] public Color ProgressNormal; + /// + /// The status bar style + /// + [EditorOrder(210)] + public StatusbarStyle Statusbar; + /// /// The arrow right icon. /// @@ -241,5 +247,27 @@ namespace FlaxEngine.GUI /// [EditorOrder(340)] public Tooltip SharedTooltip; + + /// + /// Style for the Statusbar + /// + [System.Serializable, ShowInEditor] + public struct StatusbarStyle + { + /// + /// Color of the Statusbar when in Play Mode + /// + public Color PlayMode; + + /// + /// Color of the Statusbar when in loading state (e.g. when importing assets) + /// + public Color Loading; + + /// + /// Color of the Statusbar in its failed state (e.g. with compilation errors) + /// + public Color Failed; + } } } diff --git a/Source/Engine/UI/GUI/Tooltip.cs b/Source/Engine/UI/GUI/Tooltip.cs index e98c07cc5..734fb078f 100644 --- a/Source/Engine/UI/GUI/Tooltip.cs +++ b/Source/Engine/UI/GUI/Tooltip.cs @@ -181,6 +181,9 @@ namespace FlaxEngine.GUI private void WrapPosition(ref Float2 locationSS, float flipOffset = 0.0f) { + if (_showTarget?.RootWindow == null) + return; + // Calculate popup direction var dpiScale = _showTarget.RootWindow.DpiScale; var dpiSize = Size * dpiScale; @@ -207,7 +210,8 @@ namespace FlaxEngine.GUI // Move window with mouse location var mousePos = Input.MouseScreenPosition; WrapPosition(ref mousePos, 10); - _window.Position = mousePos + new Float2(15, 10); + if (_window) + _window.Position = mousePos + new Float2(15, 10); // Auto hide if mouse leaves control area var location = _showTarget.PointFromScreen(mousePos); diff --git a/Source/Engine/UI/UICanvas.cs b/Source/Engine/UI/UICanvas.cs index 8cb43af62..edbec7f7d 100644 --- a/Source/Engine/UI/UICanvas.cs +++ b/Source/Engine/UI/UICanvas.cs @@ -493,7 +493,8 @@ namespace FlaxEngine if (_renderer) { #if FLAX_EDITOR - _editorTask?.RemoveCustomPostFx(_renderer); + if (_editorTask != null) + _editorTask.RemoveCustomPostFx(_renderer); #endif SceneRenderTask.RemoveGlobalCustomPostFx(_renderer); _renderer.Canvas = null; diff --git a/Source/Engine/UI/UIControl.cs b/Source/Engine/UI/UIControl.cs index dc76122c0..219a4fa4e 100644 --- a/Source/Engine/UI/UIControl.cs +++ b/Source/Engine/UI/UIControl.cs @@ -204,7 +204,7 @@ namespace FlaxEngine up = value; Internal_SetNavTargets(__unmanagedPtr, GetUnmanagedPtr(up), GetUnmanagedPtr(down), GetUnmanagedPtr(left), GetUnmanagedPtr(right)); if (_control != null) - _control.NavTargetUp = value?.Control; + _control.NavTargetUp = value != null ? value.Control : null; } } @@ -228,7 +228,7 @@ namespace FlaxEngine down = value; Internal_SetNavTargets(__unmanagedPtr, GetUnmanagedPtr(up), GetUnmanagedPtr(down), GetUnmanagedPtr(left), GetUnmanagedPtr(right)); if (_control != null) - _control.NavTargetDown = value?.Control; + _control.NavTargetDown = value != null ? value.Control : null; } } @@ -252,7 +252,7 @@ namespace FlaxEngine left = value; Internal_SetNavTargets(__unmanagedPtr, GetUnmanagedPtr(up), GetUnmanagedPtr(down), GetUnmanagedPtr(left), GetUnmanagedPtr(right)); if (_control != null) - _control.NavTargetLeft = value?.Control; + _control.NavTargetLeft = value != null ? value.Control : null; } } @@ -276,7 +276,7 @@ namespace FlaxEngine right = value; Internal_SetNavTargets(__unmanagedPtr, GetUnmanagedPtr(up), GetUnmanagedPtr(down), GetUnmanagedPtr(left), GetUnmanagedPtr(right)); if (_control != null) - _control.NavTargetRight = value?.Control; + _control.NavTargetRight = value != null ? value.Control : null; } } diff --git a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs index 20f64b92e..eff24dbf3 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/DotNetSdk.cs @@ -192,11 +192,9 @@ namespace Flax.Build case TargetPlatform.Linux: { rid = $"linux-{arch}"; - ridFallback = ""; + ridFallback = Utilities.ReadProcessOutput("dotnet", "--info").Split('\n').FirstOrDefault(x => x.StartsWith(" RID:"), "").Replace("RID:", "").Trim(); if (string.IsNullOrEmpty(dotnetPath)) dotnetPath ??= SearchForDotnetLocationLinux(); - if (dotnetPath == null) - ridFallback = Utilities.ReadProcessOutput("dotnet", "--info").Split('\n').FirstOrDefault(x => x.StartsWith(" RID:"), "").Replace("RID:", "").Trim(); break; } case TargetPlatform.Mac: diff --git a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs index 6dcc12a4f..a6684d6eb 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudio/VisualStudioProjectGenerator.cs @@ -166,12 +166,14 @@ namespace Flax.Build.Projects.VisualStudio { try { - Regex projectRegex = new Regex(@"Project\(.*\) = \""(\S+)\"", \""(\S+)\"", \""{(\S+)}\"""); + Regex projectRegex = new Regex(@"Project\(""{(\S+)}""\) = \""(\S+)\"", \""(\S+)\"", \""{(\S+)}\"""); MatchCollection matches = projectRegex.Matches(File.ReadAllText(path)); for (int i = 0; i < matches.Count; i++) { - if (matches[i].Groups[1].Value == projectName) - return Guid.ParseExact(matches[i].Groups[3].Value, "D"); + if (matches[i].Groups[1].Value.Equals("2150E333-8FDC-42A3-9474-1A3956D46DE8", StringComparison.OrdinalIgnoreCase)) + continue; + if (matches[i].Groups[2].Value == projectName) + return Guid.ParseExact(matches[i].Groups[4].Value, "D"); } } catch @@ -376,7 +378,8 @@ namespace Flax.Build.Projects.VisualStudio { if (!folderIds.TryGetValue(folderPath, out project.FolderGuid)) { - project.FolderGuid = Guid.NewGuid(); + if (!folderIds.TryGetValue(folderParents[i], out project.FolderGuid)) + project.FolderGuid = Guid.NewGuid(); folderIds.Add(folderPath, project.FolderGuid); } folderNames.Add(folderPath); @@ -479,7 +482,7 @@ namespace Flax.Build.Projects.VisualStudio { SolutionConfiguration projectConfiguration; bool build = false; - int firstFullMatch = -1, firstPlatformMatch = -1; + int firstFullMatch = -1, firstPlatformMatch = -1, firstEditorMatch = -1; for (int i = 0; i < project.Configurations.Count; i++) { var e = new SolutionConfiguration(project.Configurations[i]); @@ -492,18 +495,31 @@ namespace Flax.Build.Projects.VisualStudio { firstPlatformMatch = i; } + if (firstEditorMatch == -1 && e.Configuration == configuration.Configuration) + { + firstEditorMatch = i; + } } if (firstFullMatch != -1) { projectConfiguration = configuration; build = solution.MainProject == project || (solution.MainProject == null && project.Name == solution.Name); } - else if (firstPlatformMatch != -1) + else if (firstPlatformMatch != -1 && !configuration.Name.StartsWith("Editor.")) { + // No exact match, pick the first configuration for matching platform projectConfiguration = new SolutionConfiguration(project.Configurations[firstPlatformMatch]); } + else if (firstEditorMatch != -1 && configuration.Name.StartsWith("Editor.")) + { + // No exact match, pick the matching editor configuration for different platform. + // As an example, Editor configuration for Android projects should be remapped + // to desktop platform in order to provide working Intellisense information. + projectConfiguration = new SolutionConfiguration(project.Configurations[firstEditorMatch]); + } else { + // No match projectConfiguration = new SolutionConfiguration(project.Configurations[0]); } diff --git a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs index fdf1df4e2..887197258 100644 --- a/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs +++ b/Source/Tools/Flax.Build/Projects/VisualStudioCode/VisualStudioCodeProjectGenerator.cs @@ -155,122 +155,122 @@ namespace Flax.Build.Projects.VisualStudioCode { foreach (var project in solution.Projects) { - // C++ project - if (project.Type == TargetType.NativeCpp) + if (project.Name == "BuildScripts") + continue; + + // Skip duplicate build tasks + if (project.Name == "FlaxEngine" || (solution.MainProject.Name != "Flax" && solution.MainProject != project)) + continue; + + bool defaultTask = project == solution.MainProject; + foreach (var configuration in project.Configurations) { - bool defaultTask = project == solution.MainProject; - foreach (var configuration in project.Configurations) + var target = configuration.Target; + var name = project.Name + '|' + configuration.Name; + + json.BeginObject(); + + json.AddField("label", name); + + bool isDefaultTask = defaultTask && configuration.Configuration == TargetConfiguration.Development && configuration.Platform == Platform.BuildPlatform.Target; + + json.BeginObject("group"); { - var target = configuration.Target; - var name = project.Name + '|' + configuration.Name; - - json.BeginObject(); - - json.AddField("label", name); - - if (defaultTask && configuration.Configuration == TargetConfiguration.Development && configuration.Platform == Platform.BuildPlatform.Target) - { - defaultTask = false; - json.BeginObject("group"); - { - json.AddField("kind", "build"); - json.AddField("isDefault", true); - } - json.EndObject(); - } - else - { - json.AddField("group", "build"); - } - - switch (Platform.BuildPlatform.Target) - { - case TargetPlatform.Windows: - { - json.AddField("command", buildToolPath); - json.BeginArray("args"); - { - json.AddUnnamedField("-build"); - json.AddUnnamedField("-log"); - json.AddUnnamedField("-mutex"); - json.AddUnnamedField(string.Format("\\\"-workspace={0}\\\"", buildToolWorkspace)); - json.AddUnnamedField(string.Format("-arch={0}", configuration.ArchitectureName)); - json.AddUnnamedField(string.Format("-configuration={0}", configuration.ConfigurationName)); - json.AddUnnamedField(string.Format("-platform={0}", configuration.PlatformName)); - json.AddUnnamedField(string.Format("-buildTargets={0}", target.Name)); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - json.AddUnnamedField(string.Format("-compiler={0}", Configuration.Compiler)); - } - json.EndArray(); - - json.AddField("type", "shell"); - - json.BeginObject("options"); - { - json.AddField("cwd", buildToolWorkspace); - } - json.EndObject(); - break; - } - case TargetPlatform.Linux: - { - json.AddField("command", buildToolPath); - json.BeginArray("args"); - { - json.AddUnnamedField("--build"); - json.AddUnnamedField("--log"); - json.AddUnnamedField("--mutex"); - json.AddUnnamedField(string.Format("--workspace=\\\"{0}\\\"", buildToolWorkspace)); - json.AddUnnamedField(string.Format("--arch={0}", configuration.Architecture)); - json.AddUnnamedField(string.Format("--configuration={0}", configuration.ConfigurationName)); - json.AddUnnamedField(string.Format("--platform={0}", configuration.PlatformName)); - json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); - } - json.EndArray(); - - json.AddField("type", "shell"); - - json.BeginObject("options"); - { - json.AddField("cwd", buildToolWorkspace); - } - json.EndObject(); - break; - } - case TargetPlatform.Mac: - { - json.AddField("command", buildToolPath); - json.BeginArray("args"); - { - json.AddUnnamedField("--build"); - json.AddUnnamedField("--log"); - json.AddUnnamedField("--mutex"); - json.AddUnnamedField(string.Format("--workspace=\\\"{0}\\\"", buildToolWorkspace)); - json.AddUnnamedField(string.Format("--arch={0}", configuration.Architecture)); - json.AddUnnamedField(string.Format("--configuration={0}", configuration.ConfigurationName)); - json.AddUnnamedField(string.Format("--platform={0}", configuration.PlatformName)); - json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); - if (!string.IsNullOrEmpty(Configuration.Compiler)) - json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); - } - json.EndArray(); - - json.AddField("type", "shell"); - - json.BeginObject("options"); - { - json.AddField("cwd", buildToolWorkspace); - } - json.EndObject(); - break; - } - default: throw new Exception("Visual Code project generator does not support current platform."); - } - - json.EndObject(); + json.AddField("kind", "build"); + json.AddField("isDefault", isDefaultTask); } + json.EndObject(); + + if (isDefaultTask) + defaultTask = false; + + switch (Platform.BuildPlatform.Target) + { + case TargetPlatform.Windows: + { + json.AddField("command", buildToolPath); + json.BeginArray("args"); + { + json.AddUnnamedField("-build"); + json.AddUnnamedField("-log"); + json.AddUnnamedField("-mutex"); + json.AddUnnamedField(string.Format("\\\"-workspace={0}\\\"", buildToolWorkspace)); + json.AddUnnamedField(string.Format("-arch={0}", configuration.ArchitectureName)); + json.AddUnnamedField(string.Format("-configuration={0}", configuration.ConfigurationName)); + json.AddUnnamedField(string.Format("-platform={0}", configuration.PlatformName)); + json.AddUnnamedField(string.Format("-buildTargets={0}", target.Name)); + if (!string.IsNullOrEmpty(Configuration.Compiler)) + json.AddUnnamedField(string.Format("-compiler={0}", Configuration.Compiler)); + } + json.EndArray(); + + json.AddField("type", "shell"); + + json.BeginObject("options"); + { + json.AddField("cwd", buildToolWorkspace); + } + json.EndObject(); + break; + } + case TargetPlatform.Linux: + { + json.AddField("command", buildToolPath); + json.BeginArray("args"); + { + json.AddUnnamedField("--build"); + json.AddUnnamedField("--log"); + json.AddUnnamedField("--mutex"); + json.AddUnnamedField(string.Format("--workspace=\\\"{0}\\\"", buildToolWorkspace)); + json.AddUnnamedField(string.Format("--arch={0}", configuration.Architecture)); + json.AddUnnamedField(string.Format("--configuration={0}", configuration.ConfigurationName)); + json.AddUnnamedField(string.Format("--platform={0}", configuration.PlatformName)); + json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); + if (!string.IsNullOrEmpty(Configuration.Compiler)) + json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); + } + json.EndArray(); + + json.AddField("type", "shell"); + + json.BeginObject("options"); + { + json.AddField("cwd", buildToolWorkspace); + } + json.EndObject(); + break; + } + case TargetPlatform.Mac: + { + json.AddField("command", buildToolPath); + json.BeginArray("args"); + { + json.AddUnnamedField("--build"); + json.AddUnnamedField("--log"); + json.AddUnnamedField("--mutex"); + json.AddUnnamedField(string.Format("--workspace=\\\"{0}\\\"", buildToolWorkspace)); + json.AddUnnamedField(string.Format("--arch={0}", configuration.Architecture)); + json.AddUnnamedField(string.Format("--configuration={0}", configuration.ConfigurationName)); + json.AddUnnamedField(string.Format("--platform={0}", configuration.PlatformName)); + json.AddUnnamedField(string.Format("--buildTargets={0}", target.Name)); + if (!string.IsNullOrEmpty(Configuration.Compiler)) + json.AddUnnamedField(string.Format("--compiler={0}", Configuration.Compiler)); + } + json.EndArray(); + + json.AddField("type", "shell"); + + json.BeginObject("options"); + { + json.AddField("cwd", buildToolWorkspace); + } + json.EndObject(); + break; + } + default: throw new Exception("Visual Code project generator does not support current platform."); + } + + json.EndObject(); } } } @@ -281,6 +281,10 @@ namespace Flax.Build.Projects.VisualStudioCode json.Save(Path.Combine(vsCodeFolder, "tasks.json")); } + bool hasNativeProjects = solution.Projects.Any(x => x.Type == TargetType.NativeCpp); + bool hasMonoProjects = solution.Projects.Any(x => x.Type == TargetType.DotNet); + bool hasDotnetProjects = solution.Projects.Any(x => x.Type == TargetType.DotNetCore); + // Create launch file using (var json = new JsonWriter()) { @@ -292,9 +296,15 @@ namespace Flax.Build.Projects.VisualStudioCode { foreach (var project in solution.Projects) { + if (project.Name == "BuildScripts") + continue; // C++ project if (project.Type == TargetType.NativeCpp) { + // Skip generating launch profiles for plugins and dependencies + if (solution.MainProject.Name != "Flax" && project.Name != "Flax.Build" && solution.MainProject.WorkspaceRootPath != project.WorkspaceRootPath) + continue; + foreach (var configuration in project.Configurations) { var name = project.Name + '|' + configuration.Name; @@ -314,115 +324,49 @@ namespace Flax.Build.Projects.VisualStudioCode json.AddField("preLaunchTask", name); json.AddField("cwd", buildToolWorkspace); - switch (Platform.BuildPlatform.Target) + WriteNativePlatformLaunchSettings(json, configuration.Platform); + + if (outputType != TargetOutputType.Executable && configuration.Name.StartsWith("Editor.")) { - case TargetPlatform.Windows: - if (configuration.Platform == TargetPlatform.Windows && outputType != TargetOutputType.Executable && configuration.Name.StartsWith("Editor.")) + if (configuration.Platform == TargetPlatform.Windows) { var editorFolder = configuration.Architecture == TargetArchitecture.x64 ? "Win64" : "Win32"; json.AddField("program", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", editorFolder, configuration.ConfigurationName, "FlaxEditor.exe")); - json.BeginArray("args"); + } + else if (configuration.Platform == TargetPlatform.Linux) + json.AddField("program", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", "Linux", configuration.ConfigurationName, "FlaxEditor")); + else if (configuration.Platform == TargetPlatform.Mac) + json.AddField("program", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", "Mac", configuration.ConfigurationName, "FlaxEditor")); + + json.BeginArray("args"); + { + json.AddUnnamedField("-project"); + json.AddUnnamedField(buildToolWorkspace); + json.AddUnnamedField("-skipCompile"); + if (hasMonoProjects) { - json.AddUnnamedField("-project"); - json.AddUnnamedField(buildToolWorkspace); - json.AddUnnamedField("-skipCompile"); json.AddUnnamedField("-debug"); json.AddUnnamedField("127.0.0.1:55555"); } - json.EndArray(); } - else - { - json.AddField("program", outputTargetFilePath); - } - break; - case TargetPlatform.Linux: - if (configuration.Platform == TargetPlatform.Linux && (outputType != TargetOutputType.Executable || project.BaseName == "Flax") && configuration.Name.StartsWith("Editor.")) - { - json.AddField("program", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", "Linux", configuration.ConfigurationName, "FlaxEditor")); - } - else - { - json.AddField("program", outputTargetFilePath); - } - if (configuration.Platform == TargetPlatform.Linux) - { - json.AddField("MIMode", "gdb"); - json.BeginArray("setupCommands"); - { - json.BeginObject(); - json.AddField("description", "Enable pretty-printing for gdb"); - json.AddField("text", "-enable-pretty-printing"); - json.AddField("ignoreFailures", true); - json.EndObject(); - - // Ignore signals used by C# runtime - json.BeginObject(); - json.AddField("description", "ignore SIG34 signal"); - json.AddField("text", "handle SIG34 nostop noprint pass"); - json.EndObject(); - json.BeginObject(); - json.AddField("description", "ignore SIG35 signal"); - json.AddField("text", "handle SIG35 nostop noprint pass"); - json.EndObject(); - json.BeginObject(); - json.AddField("description", "ignore SIG36 signal"); - json.AddField("text", "handle SIG36 nostop noprint pass"); - json.EndObject(); - json.BeginObject(); - json.AddField("description", "ignore SIG357 signal"); - json.AddField("text", "handle SIG37 nostop noprint pass"); - json.EndObject(); - } - json.EndArray(); - json.BeginArray("args"); - { - json.AddUnnamedField("--std"); - if (outputType != TargetOutputType.Executable && configuration.Name.StartsWith("Editor.")) - { - json.AddUnnamedField("--project"); - json.AddUnnamedField(buildToolWorkspace); - json.AddUnnamedField("--skipCompile"); - } - } - json.EndArray(); - } - break; - case TargetPlatform.Mac: - if (configuration.Platform == TargetPlatform.Mac && (outputType != TargetOutputType.Executable || project.BaseName == "Flax") && configuration.Name.StartsWith("Editor.")) - { - json.AddField("program", Path.Combine(Globals.EngineRoot, "Binaries", "Editor", "Mac", configuration.ConfigurationName, "FlaxEditor")); - } - else - { - json.AddField("program", outputTargetFilePath); - } - if (configuration.Platform == TargetPlatform.Mac) - { - json.AddField("MIMode", "lldb"); - json.BeginArray("args"); - { - json.AddUnnamedField("--std"); - if (outputType != TargetOutputType.Executable && configuration.Name.StartsWith("Editor.")) - { - json.AddUnnamedField("--project"); - json.AddUnnamedField(buildToolWorkspace); - json.AddUnnamedField("--skipCompile"); - } - } - json.EndArray(); - } - break; + json.EndArray(); } - switch (configuration.Platform) + else { - case TargetPlatform.Windows: - json.AddField("stopAtEntry", false); - json.AddField("externalConsole", true); - break; - case TargetPlatform.Linux: - break; + json.AddField("program", outputTargetFilePath); + json.BeginArray("args"); + { + if (configuration.Platform == TargetPlatform.Linux || configuration.Platform == TargetPlatform.Mac) + json.AddUnnamedField("--std"); + if (hasMonoProjects) + { + json.AddUnnamedField("-debug"); + json.AddUnnamedField("127.0.0.1:55555"); + } + } + json.EndArray(); } + json.AddField("visualizerFile", Path.Combine(Globals.EngineRoot, "Source", "flax.natvis")); } json.EndObject(); @@ -431,16 +375,9 @@ namespace Flax.Build.Projects.VisualStudioCode // C# project else if (project.Type == TargetType.DotNetCore) { - // TODO: Skip generating launch profiles for plugins and dependencies - - json.BeginObject(); - { - json.AddField("type", "coreclr"); - json.AddField("name", project.Name + " (C# attach Editor)"); - json.AddField("request", "attach"); - json.AddField("processName", "FlaxEditor"); - } - json.EndObject(); + // Skip generating launch profiles for plugins and dependencies + if (solution.MainProject.WorkspaceRootPath != project.WorkspaceRootPath) + continue; foreach (var configuration in project.Configurations) { @@ -484,24 +421,54 @@ namespace Flax.Build.Projects.VisualStudioCode json.EndObject(); } } - // Mono C# project - else if (project.Type == TargetType.DotNet) - { - foreach (var configuration in project.Configurations) - { - json.BeginObject(); - { - json.AddField("type", "mono"); - json.AddField("name", project.Name + " (C# attach)" + '|' + configuration.Name); - json.AddField("request", "attach"); - json.AddField("address", "localhost"); - json.AddField("port", 55555); - } - json.EndObject(); - } - } } } + + if (hasNativeProjects) + { + foreach (var platform in solution.Projects.SelectMany(x => x.Configurations).Select(x => x.Platform).Distinct()) + { + json.BeginObject(); + { + if (platform == TargetPlatform.Windows) + json.AddField("type", "cppvsdbg"); + else + json.AddField("type", "cppdbg"); + json.AddField("name", solution.Name + " (Attach Editor)"); + json.AddField("request", "attach"); + json.AddField("processId", "${command:pickProcess}"); // Does not seem to be possible to attach by process name? + + WriteNativePlatformLaunchSettings(json, platform); + + json.AddField("visualizerFile", Path.Combine(Globals.EngineRoot, "Source", "flax.natvis")); + } + json.EndObject(); + } + } + if (hasDotnetProjects) + { + json.BeginObject(); + { + json.AddField("type", "coreclr"); + json.AddField("name", solution.Name + " (C# Attach Editor)"); + json.AddField("request", "attach"); + json.AddField("processName", "FlaxEditor"); + } + json.EndObject(); + } + if (hasMonoProjects) + { + json.BeginObject(); + { + json.AddField("type", "mono"); + json.AddField("name", solution.Name + " (C# Attach)"); + json.AddField("request", "attach"); + json.AddField("address", "localhost"); + json.AddField("port", 55555); + } + json.EndObject(); + } + json.EndArray(); } json.EndRootObject(); @@ -509,6 +476,59 @@ namespace Flax.Build.Projects.VisualStudioCode json.Save(Path.Combine(vsCodeFolder, "launch.json")); } + static void WriteNativePlatformLaunchSettings(JsonWriter json, TargetPlatform platform) + { + switch (Platform.BuildPlatform.Target) + { + case TargetPlatform.Linux: + if (platform == TargetPlatform.Linux) + { + json.AddField("MIMode", "gdb"); + json.BeginArray("setupCommands"); + { + json.BeginObject(); + json.AddField("description", "Enable pretty-printing for gdb"); + json.AddField("text", "-enable-pretty-printing"); + json.AddField("ignoreFailures", true); + json.EndObject(); + + // Ignore signals used by C# runtime + json.BeginObject(); + json.AddField("description", "ignore SIG34 signal"); + json.AddField("text", "handle SIG34 nostop noprint pass"); + json.EndObject(); + json.BeginObject(); + json.AddField("description", "ignore SIG35 signal"); + json.AddField("text", "handle SIG35 nostop noprint pass"); + json.EndObject(); + json.BeginObject(); + json.AddField("description", "ignore SIG36 signal"); + json.AddField("text", "handle SIG36 nostop noprint pass"); + json.EndObject(); + json.BeginObject(); + json.AddField("description", "ignore SIG357 signal"); + json.AddField("text", "handle SIG37 nostop noprint pass"); + json.EndObject(); + } + json.EndArray(); + } + break; + case TargetPlatform.Mac: + if (platform == TargetPlatform.Mac) + { + json.AddField("MIMode", "lldb"); + } + break; + } + switch (platform) + { + case TargetPlatform.Windows: + json.AddField("stopAtEntry", false); + json.AddField("externalConsole", true); + break; + } + } + // Create C++ properties file using (var json = new JsonWriter()) {