diff --git a/Development/Documentation/mono.md b/Development/Documentation/mono.md index d292ebb3d..4a880b7a0 100644 --- a/Development/Documentation/mono.md +++ b/Development/Documentation/mono.md @@ -2,6 +2,8 @@ Custom fork: [https://github.com/FlaxEngine/mono](https://github.com/FlaxEngine/mono) with custom features for C# assemblies hot-reloading at runtime without domain unload (more: [https://flaxengine.com/blog/flax-facts-16-scripts-hot-reload/](https://flaxengine.com/blog/flax-facts-16-scripts-hot-reload/)). +Startup docs about building mono: [https://www.mono-project.com/docs/compiling-mono/](https://www.mono-project.com/docs/compiling-mono/) + ### Notes Some useful notes and tips for devs: diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp index 1396214ca..aee282024 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.cpp +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.cpp @@ -221,6 +221,7 @@ void CookAssetsStep::CacheData::Load(CookingData& data) { const auto settings = WindowsPlatformSettings::Get(); const bool modified = + Settings.Windows.SupportDX12 != settings->SupportDX12 || Settings.Windows.SupportDX11 != settings->SupportDX11 || Settings.Windows.SupportDX10 != settings->SupportDX10 || Settings.Windows.SupportVulkan != settings->SupportVulkan; @@ -1025,6 +1026,7 @@ bool CookAssetsStep::Perform(CookingData& data) #if PLATFORM_TOOLS_WINDOWS { const auto settings = WindowsPlatformSettings::Get(); + cache.Settings.Windows.SupportDX12 = settings->SupportDX12; cache.Settings.Windows.SupportDX11 = settings->SupportDX11; cache.Settings.Windows.SupportDX10 = settings->SupportDX10; cache.Settings.Windows.SupportVulkan = settings->SupportVulkan; diff --git a/Source/Editor/Cooker/Steps/CookAssetsStep.h b/Source/Editor/Cooker/Steps/CookAssetsStep.h index 36d0734eb..7a6163700 100644 --- a/Source/Editor/Cooker/Steps/CookAssetsStep.h +++ b/Source/Editor/Cooker/Steps/CookAssetsStep.h @@ -75,6 +75,7 @@ public: { struct { + bool SupportDX12; bool SupportDX11; bool SupportDX10; bool SupportVulkan; diff --git a/Source/Editor/Editor.cs b/Source/Editor/Editor.cs index d4afdd693..50de80e88 100644 --- a/Source/Editor/Editor.cs +++ b/Source/Editor/Editor.cs @@ -891,10 +891,10 @@ namespace FlaxEditor if (asset == null) throw new ArgumentNullException(nameof(asset)); if (asset.WaitForLoaded()) - throw new FlaxException("Failed to load asset."); + throw new Exception("Failed to load asset."); var source = Internal_GetShaderAssetSourceCode(FlaxEngine.Object.GetUnmanagedPtr(asset)); if (source == null) - throw new FlaxException("Failed to get source code."); + throw new Exception("Failed to get source code."); return source; } diff --git a/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs b/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs index 1fe3bb763..4e813fe38 100644 --- a/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/AnimationEventTrack.cs @@ -30,6 +30,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks base.Initialize(layout); var instance = (AnimEvent)Values[0]; + if (instance == null) + return; var scriptType = TypeUtils.GetObjectType(instance); var editor = CustomEditorsUtil.CreateEditor(scriptType, false); layout.Object(Values, editor); @@ -125,6 +127,52 @@ namespace FlaxEditor.GUI.Timeline.Tracks } } + internal void InitMissing(string typeName, byte[] data) + { + Type = ScriptType.Null; + IsContinuous = false; + CanDelete = true; + CanSplit = false; + CanResize = false; + TooltipText = $"Missing Anim Event Type '{typeName}'"; + Instance = null; + BackgroundColor = Color.Red; + _instanceTypeName = typeName; + _instanceData = data; + } + + internal void Load(BinaryReader stream) + { + StartFrame = (int)stream.ReadSingle(); + DurationFrames = (int)stream.ReadSingle(); + var typeName = stream.ReadStrAnsi(13); + var type = TypeUtils.GetType(typeName); + if (type == ScriptType.Null) + { + InitMissing(typeName, stream.ReadJsonBytes()); + return; + } + Init(type); + stream.ReadJson(Instance); + } + + internal void Save(BinaryWriter stream) + { + stream.Write((float)StartFrame); + stream.Write((float)DurationFrames); + if (Type != ScriptType.Null) + { + stream.WriteStrAnsi(Type.TypeName, 13); + stream.WriteJson(Instance); + } + else + { + // Missing + stream.WriteStrAnsi(_instanceTypeName, 13); + stream.WriteJsonBytes(_instanceData); + } + } + /// protected override void OnDurationFramesChanged() { @@ -137,6 +185,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks /// public override void OnDestroy() { + _instanceData = null; + _instanceTypeName = null; Type = ScriptType.Null; Object.Destroy(ref Instance); if (_isRegisteredForScriptsReload) @@ -181,14 +231,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks for (int i = 0; i < count; i++) { var m = (AnimationEventMedia)e.Media[i]; - m.StartFrame = (int)stream.ReadSingle(); - m.DurationFrames = (int)stream.ReadSingle(); - var typeName = stream.ReadStrAnsi(13); - var type = TypeUtils.GetType(typeName); - if (type == ScriptType.Null) - throw new Exception($"Unknown type {typeName}."); - m.Init(type); - stream.ReadJson(m.Instance); + m.Load(stream); } } @@ -200,10 +243,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks for (int i = 0; i < count; i++) { var m = (AnimationEventMedia)e.Media[i]; - stream.Write((float)m.StartFrame); - stream.Write((float)m.DurationFrames); - stream.WriteStrAnsi(m.Type.TypeName, 13); - stream.WriteJson(m.Instance); + m.Save(stream); } } diff --git a/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs b/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs index 96e858a9a..b5026b1b1 100644 --- a/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs +++ b/Source/Editor/GUI/Timeline/Tracks/CameraCutTrack.cs @@ -631,7 +631,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks } } if (spriteIndex == -1) - throw new FlaxException(); + throw new Exception(); atlas.Count++; _atlases[atlasIndex] = atlas; var sprite = new SpriteHandle(atlas.Texture, spriteIndex); diff --git a/Source/Editor/Modules/PrefabsModule.cs b/Source/Editor/Modules/PrefabsModule.cs index 94ae8d736..71531df2d 100644 --- a/Source/Editor/Modules/PrefabsModule.cs +++ b/Source/Editor/Modules/PrefabsModule.cs @@ -212,7 +212,7 @@ namespace FlaxEditor.Modules // Call backend if (PrefabManager.Internal_ApplyAll(FlaxEngine.Object.GetUnmanagedPtr(instance))) - throw new FlaxException("Failed to apply the prefab. See log to learn more."); + throw new Exception("Failed to apply the prefab. See log to learn more."); PrefabApplied?.Invoke(prefab, instance); } diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index cb01b4c09..8e1d98e1f 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. using System; +using System.Reflection; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; using FlaxEditor.Scripting; @@ -421,13 +422,23 @@ namespace FlaxEditor.Surface.Archetypes TryParseText = (string filterText, out object[] data) => { data = null; - if (!filterText.StartsWith("#")) - return false; - if (Color.TryParseHex(filterText, out var color)) + if (filterText.StartsWith("#") && Color.TryParseHex(filterText, out var color)) { + // Color constant from hex data = new object[] { color }; return true; } + if (filterText.Length > 2) + { + var fieldName = char.ToUpperInvariant(filterText[0]) + filterText.Substring(1).ToLowerInvariant(); + var field = typeof(Color).GetField(fieldName, BindingFlags.Public | BindingFlags.Static); + if (field != null && fieldName != "Zero") + { + // Color constant in-built + data = new object[] { field.GetValue(null) }; + return true; + } + } return false; } }, diff --git a/Source/Editor/Tools/Terrain/Paint/Mode.cs b/Source/Editor/Tools/Terrain/Paint/Mode.cs index 23b3d47f1..e0eea6186 100644 --- a/Source/Editor/Tools/Terrain/Paint/Mode.cs +++ b/Source/Editor/Tools/Terrain/Paint/Mode.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. +using System; using FlaxEditor.Tools.Terrain.Brushes; using FlaxEngine; @@ -129,9 +130,7 @@ namespace FlaxEditor.Tools.Terrain.Paint // Get the patch data (cached internally by the c++ core in editor) var sourceData = TerrainTools.GetSplatMapData(terrain, ref patch.PatchCoord, splatmapIndex); if (sourceData == null) - { - throw new FlaxException("Cannot modify terrain. Loading splatmap failed. See log for more info."); - } + throw new Exception("Cannot modify terrain. Loading splatmap failed. See log for more info."); // Record patch data before editing it if (!gizmo.CurrentEditUndoAction.HashPatch(ref patch.PatchCoord)) diff --git a/Source/Editor/Tools/Terrain/Sculpt/Mode.cs b/Source/Editor/Tools/Terrain/Sculpt/Mode.cs index 0708a2558..1e1ece566 100644 --- a/Source/Editor/Tools/Terrain/Sculpt/Mode.cs +++ b/Source/Editor/Tools/Terrain/Sculpt/Mode.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. +using System; using FlaxEditor.Tools.Terrain.Brushes; using FlaxEngine; @@ -128,9 +129,7 @@ namespace FlaxEditor.Tools.Terrain.Sculpt float* sourceHeights = EditHoles ? null : TerrainTools.GetHeightmapData(terrain, ref patch.PatchCoord); byte* sourceHoles = EditHoles ? TerrainTools.GetHolesMaskData(terrain, ref patch.PatchCoord) : null; if (sourceHeights == null && sourceHoles == null) - { - throw new FlaxException("Cannot modify terrain. Loading heightmap failed. See log for more info."); - } + throw new Exception("Cannot modify terrain. Loading heightmap failed. See log for more info."); // Record patch data before editing it if (!gizmo.CurrentEditUndoAction.HashPatch(ref patch.PatchCoord)) diff --git a/Source/Editor/Tools/Terrain/Undo/EditTerrainHeightMapAction.cs b/Source/Editor/Tools/Terrain/Undo/EditTerrainHeightMapAction.cs index 833e2b8e9..252263902 100644 --- a/Source/Editor/Tools/Terrain/Undo/EditTerrainHeightMapAction.cs +++ b/Source/Editor/Tools/Terrain/Undo/EditTerrainHeightMapAction.cs @@ -37,7 +37,7 @@ namespace FlaxEditor.Tools.Terrain.Undo var offset = Int2.Zero; var size = new Int2((int)Mathf.Sqrt(_heightmapLength)); if (TerrainTools.ModifyHeightMap(Terrain, ref patchCoord, (float*)data, ref offset, ref size)) - throw new FlaxException("Failed to modify the heightmap."); + throw new Exception("Failed to modify the heightmap."); } } } diff --git a/Source/Editor/Tools/Terrain/Undo/EditTerrainHolesMapAction.cs b/Source/Editor/Tools/Terrain/Undo/EditTerrainHolesMapAction.cs index 9f81f14ba..d8ebe425d 100644 --- a/Source/Editor/Tools/Terrain/Undo/EditTerrainHolesMapAction.cs +++ b/Source/Editor/Tools/Terrain/Undo/EditTerrainHolesMapAction.cs @@ -37,7 +37,7 @@ namespace FlaxEditor.Tools.Terrain.Undo var offset = Int2.Zero; var size = new Int2((int)Mathf.Sqrt(_heightmapLength)); if (TerrainTools.ModifyHolesMask(Terrain, ref patchCoord, (byte*)data, ref offset, ref size)) - throw new FlaxException("Failed to modify the terrain holes."); + throw new Exception("Failed to modify the terrain holes."); } } } diff --git a/Source/Editor/Tools/Terrain/Undo/EditTerrainSplatMapAction.cs b/Source/Editor/Tools/Terrain/Undo/EditTerrainSplatMapAction.cs index b4b1d3e97..dfe6e553d 100644 --- a/Source/Editor/Tools/Terrain/Undo/EditTerrainSplatMapAction.cs +++ b/Source/Editor/Tools/Terrain/Undo/EditTerrainSplatMapAction.cs @@ -37,7 +37,7 @@ namespace FlaxEditor.Tools.Terrain.Undo var offset = Int2.Zero; var size = new Int2((int)Mathf.Sqrt(_heightmapLength)); if (TerrainTools.ModifySplatMap(Terrain, ref patchCoord, (int)tag, (Color32*)data, ref offset, ref size)) - throw new FlaxException("Failed to modify the splatmap."); + throw new Exception("Failed to modify the splatmap."); } } } diff --git a/Source/Editor/Undo/Actions/BreakPrefabLinkAction.cs b/Source/Editor/Undo/Actions/BreakPrefabLinkAction.cs index a471c166b..d2db66792 100644 --- a/Source/Editor/Undo/Actions/BreakPrefabLinkAction.cs +++ b/Source/Editor/Undo/Actions/BreakPrefabLinkAction.cs @@ -68,7 +68,7 @@ namespace FlaxEditor.Actions if (actor == null) throw new ArgumentNullException(nameof(actor)); if (!actor.HasPrefabLink) - throw new FlaxException("Cannot register missing prefab link."); + throw new Exception("Cannot register missing prefab link."); return new BreakPrefabLinkAction(false, actor); } @@ -102,11 +102,11 @@ namespace FlaxEditor.Actions private void DoLink() { if (_prefabObjectIds == null) - throw new FlaxException("Cannot link prefab. Missing objects Ids mapping."); + throw new Exception("Cannot link prefab. Missing objects Ids mapping."); var actor = Object.Find(ref _actorId); if (actor == null) - throw new FlaxException("Cannot link prefab. Missing actor."); + throw new Exception("Cannot link prefab. Missing actor."); // Restore cached links foreach (var e in _prefabObjectIds) @@ -149,9 +149,9 @@ namespace FlaxEditor.Actions { var actor = Object.Find(ref _actorId); if (actor == null) - throw new FlaxException("Cannot break prefab link. Missing actor."); + throw new Exception("Cannot break prefab link. Missing actor."); if (!actor.HasPrefabLink) - throw new FlaxException("Cannot break missing prefab link."); + throw new Exception("Cannot break missing prefab link."); if (_prefabObjectIds == null) _prefabObjectIds = new Dictionary(1024); diff --git a/Source/Editor/Utilities/DuplicateScenes.cs b/Source/Editor/Utilities/DuplicateScenes.cs index 87a375e1b..e9ff1b6f9 100644 --- a/Source/Editor/Utilities/DuplicateScenes.cs +++ b/Source/Editor/Utilities/DuplicateScenes.cs @@ -72,7 +72,7 @@ namespace FlaxEditor.Utilities if (Level.UnloadAllScenes()) { Profiler.EndEvent(); - throw new FlaxException("Failed to unload scenes."); + throw new Exception("Failed to unload scenes."); } FlaxEngine.Scripting.FlushRemovedObjects(); @@ -82,7 +82,7 @@ namespace FlaxEditor.Utilities if (noScenes != null && noScenes.Length != 0) { Profiler.EndEvent(); - throw new FlaxException("Failed to unload scenes."); + throw new Exception("Failed to unload scenes."); } } @@ -110,7 +110,7 @@ namespace FlaxEditor.Utilities if (scene == null) { Profiler.EndEvent(); - throw new FlaxException("Failed to deserialize scene"); + throw new Exception("Failed to deserialize scene"); } } @@ -131,7 +131,7 @@ namespace FlaxEditor.Utilities if (Level.UnloadAllScenes()) { Profiler.EndEvent(); - throw new FlaxException("Failed to unload scenes."); + throw new Exception("Failed to unload scenes."); } FlaxEngine.Scripting.FlushRemovedObjects(); Profiler.EndEvent(); @@ -154,7 +154,7 @@ namespace FlaxEditor.Utilities if (scene == null) { Profiler.EndEvent(); - throw new FlaxException("Failed to deserialize scene"); + throw new Exception("Failed to deserialize scene"); } // Restore `dirty` state diff --git a/Source/Editor/Viewport/Previews/IESProfilePreview.cs b/Source/Editor/Viewport/Previews/IESProfilePreview.cs index 9ed66c1bf..aaec77bc6 100644 --- a/Source/Editor/Viewport/Previews/IESProfilePreview.cs +++ b/Source/Editor/Viewport/Previews/IESProfilePreview.cs @@ -1,6 +1,8 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. +using System; using FlaxEngine; +using Object = FlaxEngine.Object; namespace FlaxEditor.Viewport.Previews { @@ -39,7 +41,7 @@ namespace FlaxEditor.Viewport.Previews // Wait for base (don't want to async material parameters set due to async loading) if (baseMaterial == null || baseMaterial.WaitForLoaded()) - throw new FlaxException("Cannot load IES Profile preview material."); + throw new Exception("Cannot load IES Profile preview material."); // Create preview material (virtual) _previewMaterial = baseMaterial.CreateVirtualInstance(); diff --git a/Source/Editor/Viewport/Previews/PrefabPreview.cs b/Source/Editor/Viewport/Previews/PrefabPreview.cs index c5ad97455..7f908c141 100644 --- a/Source/Editor/Viewport/Previews/PrefabPreview.cs +++ b/Source/Editor/Viewport/Previews/PrefabPreview.cs @@ -1,5 +1,6 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. +using System; using FlaxEngine; using Object = FlaxEngine.Object; @@ -54,7 +55,7 @@ namespace FlaxEditor.Viewport.Previews if (instance == null) { _prefab = null; - throw new FlaxException("Failed to spawn a prefab for the preview."); + throw new Exception("Failed to spawn a prefab for the preview."); } // Set instance diff --git a/Source/Editor/Viewport/Previews/TexturePreview.cs b/Source/Editor/Viewport/Previews/TexturePreview.cs index 278fd6c2b..09e7016e5 100644 --- a/Source/Editor/Viewport/Previews/TexturePreview.cs +++ b/Source/Editor/Viewport/Previews/TexturePreview.cs @@ -319,10 +319,10 @@ namespace FlaxEditor.Viewport.Previews // Create preview material (virtual) var baseMaterial = FlaxEngine.Content.LoadAsyncInternal("Editor/TexturePreviewMaterial"); if (baseMaterial == null) - throw new FlaxException("Cannot load texture preview material."); + throw new Exception("Cannot load texture preview material."); _previewMaterial = baseMaterial.CreateVirtualInstance(); if (_previewMaterial == null) - throw new FlaxException("Failed to create virtual material instance for preview material."); + throw new Exception("Failed to create virtual material instance for preview material."); // Add widgets if (useWidgets) diff --git a/Source/Editor/Windows/OutputLogWindow.cs b/Source/Editor/Windows/OutputLogWindow.cs index 1005bb136..b85a3f04c 100644 --- a/Source/Editor/Windows/OutputLogWindow.cs +++ b/Source/Editor/Windows/OutputLogWindow.cs @@ -482,7 +482,6 @@ namespace FlaxEditor.Windows continue; var startIndex = _textBuffer.Length; - switch (_timestampsFormats) { case InterfaceOptions.TimestampsFormats.Utc: @@ -496,12 +495,12 @@ namespace FlaxEditor.Windows _textBuffer.AppendFormat("[ {0:00}:{1:00}:{2:00}.{3:000} ]: ", diff.Hours, diff.Minutes, diff.Seconds, diff.Milliseconds); break; } - if (_showLogType) { _textBuffer.AppendFormat("[{0}] ", entry.Level); } + var prefixLength = _textBuffer.Length - startIndex; if (entry.Message.IndexOf('\r') != -1) entry.Message = entry.Message.Replace("\r", ""); _textBuffer.Append(entry.Message); @@ -548,27 +547,34 @@ namespace FlaxEditor.Windows if (textBlock.Range.Length > 0) { // Parse compilation error/warning - var match = _compileRegex.Match(entryText, line.FirstCharIndex, textBlock.Range.Length); - if (match.Success) + var regexStart = line.FirstCharIndex; + if (j == 0) + regexStart += prefixLength; + var regexLength = line.LastCharIndex - regexStart; + if (regexLength > 0) { - switch (match.Groups["level"].Value) + var match = _compileRegex.Match(entryText, regexStart, regexLength); + if (match.Success) { - case "error": - textBlock.Style = _output.ErrorStyle; - break; - case "warning": - textBlock.Style = _output.WarningStyle; - break; + switch (match.Groups["level"].Value) + { + case "error": + textBlock.Style = _output.ErrorStyle; + break; + case "warning": + textBlock.Style = _output.WarningStyle; + break; + } + textBlock.Tag = new TextBlockTag + { + Type = TextBlockTag.Types.CodeLocation, + Url = match.Groups["path"].Value, + Line = int.Parse(match.Groups["line"].Value), + }; } - textBlock.Tag = new TextBlockTag - { - Type = TextBlockTag.Types.CodeLocation, - Url = match.Groups["path"].Value, - Line = int.Parse(match.Groups["line"].Value), - }; + // TODO: parsing hyperlinks with link + // TODO: parsing file paths with link } - // TODO: parsing hyperlinks with link - // TODO: parsing file paths with link } prevBlockBottom += line.Size.Y; diff --git a/Source/Editor/Windows/SceneTreeWindow.cs b/Source/Editor/Windows/SceneTreeWindow.cs index 652cc2b6e..517f50252 100644 --- a/Source/Editor/Windows/SceneTreeWindow.cs +++ b/Source/Editor/Windows/SceneTreeWindow.cs @@ -326,7 +326,7 @@ namespace FlaxEditor.Windows _isUpdatingSelection = false; } - + private bool ValidateDragAsset(AssetItem assetItem) { return assetItem.OnEditorDrag(this); @@ -417,7 +417,7 @@ namespace FlaxEditor.Windows public override DragDropEffect OnDragEnter(ref Vector2 location, DragData data) { var result = base.OnDragEnter(ref location, data); - if (result == DragDropEffect.None && Editor.StateMachine.CurrentState.CanEditScene) + if (Editor.StateMachine.CurrentState.CanEditScene) { if (_dragHandlers == null) _dragHandlers = new DragHandlers(); @@ -426,14 +426,14 @@ namespace FlaxEditor.Windows _dragAssets = new DragAssets(ValidateDragAsset); _dragHandlers.Add(_dragAssets); } - if (_dragAssets.OnDragEnter(data)) + if (_dragAssets.OnDragEnter(data) && result == DragDropEffect.None) return _dragAssets.Effect; if (_dragActorType == null) { _dragActorType = new DragActorType(ValidateDragActorType); _dragHandlers.Add(_dragActorType); } - if (_dragActorType.OnDragEnter(data)) + if (_dragActorType.OnDragEnter(data) && result == DragDropEffect.None) return _dragActorType.Effect; } return result; diff --git a/Source/Engine/Content/JsonAsset.cpp b/Source/Engine/Content/JsonAsset.cpp index e8aa901d9..2332181b9 100644 --- a/Source/Engine/Content/JsonAsset.cpp +++ b/Source/Engine/Content/JsonAsset.cpp @@ -281,9 +281,10 @@ bool JsonAsset::CreateInstance() void JsonAsset::DeleteInstance() { - ASSERT_LOW_LAYER(Instance && _dtor); - InstanceType = ScriptingTypeHandle(); + if (!Instance || !_dtor) + return; _dtor(Instance); + InstanceType = ScriptingTypeHandle(); Allocator::Free(Instance); Instance = nullptr; _dtor = nullptr; diff --git a/Source/Engine/Engine/FlaxException.cs b/Source/Engine/Engine/FlaxException.cs deleted file mode 100644 index 147b00c4c..000000000 --- a/Source/Engine/Engine/FlaxException.cs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. - -using System; - -namespace FlaxEngine -{ - /// - /// Flax exception object. - /// - /// - [Serializable] - public class FlaxException : SystemException - { - /// - /// Initializes a new instance of the class. - /// - public FlaxException() - : base("A Flax runtime error occurred!") - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The message that describes the error. - public FlaxException(string message) - : base(message) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The error message that explains the reason for the exception. - /// The exception that is the cause of the current exception. If the parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception. - public FlaxException(string message, Exception innerException) - : base(message, innerException) - { - } - } -} diff --git a/Source/Engine/Graphics/Mesh.cs b/Source/Engine/Graphics/Mesh.cs index 2cdcc73b1..25129137c 100644 --- a/Source/Engine/Graphics/Mesh.cs +++ b/Source/Engine/Graphics/Mesh.cs @@ -154,7 +154,7 @@ namespace FlaxEngine uv, colors )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -201,7 +201,7 @@ namespace FlaxEngine Utils.ExtractArrayFromList(uv), Utils.ExtractArrayFromList(colors) )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -247,7 +247,7 @@ namespace FlaxEngine uv, colors )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -294,7 +294,7 @@ namespace FlaxEngine Utils.ExtractArrayFromList(uv), Utils.ExtractArrayFromList(colors) )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -341,7 +341,7 @@ namespace FlaxEngine uv, colors )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -388,7 +388,7 @@ namespace FlaxEngine Utils.ExtractArrayFromList(uv), Utils.ExtractArrayFromList(colors) )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -412,7 +412,7 @@ namespace FlaxEngine triangles.Length / 3, triangles )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -436,7 +436,7 @@ namespace FlaxEngine triangles.Count / 3, Utils.ExtractArrayFromList(triangles) )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -460,7 +460,7 @@ namespace FlaxEngine triangles.Length / 3, triangles )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -484,7 +484,7 @@ namespace FlaxEngine triangles.Count / 3, Utils.ExtractArrayFromList(triangles) )) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } internal enum InternalBufferType @@ -506,7 +506,7 @@ namespace FlaxEngine var vertices = VertexCount; var result = new Vertex0[vertices]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -520,7 +520,7 @@ namespace FlaxEngine var vertices = VertexCount; var result = new Vertex1[vertices]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB1)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -540,7 +540,7 @@ namespace FlaxEngine var vertices = VertexCount; var result = new Vertex2[vertices]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB2)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -597,7 +597,7 @@ namespace FlaxEngine var triangles = TriangleCount; var result = new uint[triangles * 3]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -612,7 +612,7 @@ namespace FlaxEngine var triangles = TriangleCount; var result = new ushort[triangles * 3]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } } diff --git a/Source/Engine/Graphics/SkinnedMesh.cs b/Source/Engine/Graphics/SkinnedMesh.cs index d59f619a7..5ccb25e46 100644 --- a/Source/Engine/Graphics/SkinnedMesh.cs +++ b/Source/Engine/Graphics/SkinnedMesh.cs @@ -131,7 +131,7 @@ namespace FlaxEngine throw new ArgumentOutOfRangeException(nameof(uv)); if (Internal_UpdateMeshUInt(__unmanagedPtr, vertices, triangles, blendIndices, blendWeights, normals, tangents, uv)) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -167,7 +167,7 @@ namespace FlaxEngine throw new ArgumentOutOfRangeException(nameof(uv)); if (Internal_UpdateMeshUInt(__unmanagedPtr, vertices, triangles, blendIndices, blendWeights, normals, tangents, uv)) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } /// @@ -203,7 +203,7 @@ namespace FlaxEngine throw new ArgumentOutOfRangeException(nameof(uv)); if (Internal_UpdateMeshUShort(__unmanagedPtr, vertices, triangles, blendIndices, blendWeights, normals, tangents, uv)) - throw new FlaxException("Failed to update mesh data."); + throw new Exception("Failed to update mesh data."); } internal enum InternalBufferType @@ -223,7 +223,7 @@ namespace FlaxEngine var vertices = VertexCount; var result = new Vertex0[vertices]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.VB0)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -268,7 +268,7 @@ namespace FlaxEngine var triangles = TriangleCount; var result = new uint[triangles * 3]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB32)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } @@ -283,7 +283,7 @@ namespace FlaxEngine var triangles = TriangleCount; var result = new ushort[triangles * 3]; if (Internal_DownloadBuffer(__unmanagedPtr, forceGpu, result, (int)InternalBufferType.IB16)) - throw new FlaxException("Failed to download mesh data."); + throw new Exception("Failed to download mesh data."); return result; } } diff --git a/Source/Engine/Graphics/TextureBase.cs b/Source/Engine/Graphics/TextureBase.cs index 63f17cc09..19ae402d7 100644 --- a/Source/Engine/Graphics/TextureBase.cs +++ b/Source/Engine/Graphics/TextureBase.cs @@ -177,7 +177,7 @@ namespace FlaxEngine // Call backend if (Internal_Init(__unmanagedPtr, new IntPtr(&t))) - throw new FlaxException("Failed to init texture data."); + throw new Exception("Failed to init texture data."); } } diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp index b0cfb30f8..1b08c06ec 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.cpp @@ -266,6 +266,20 @@ bool GPUDeviceDX11::Init() } UpdateOutputs(adapter); + ComPtr factory5; + _factoryDXGI->QueryInterface(IID_PPV_ARGS(&factory5)); + if (factory5) + { + BOOL allowTearing; + if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))) + && allowTearing +#if PLATFORM_WINDOWS + && GetModuleHandleA("renderdoc.dll") == nullptr // Disable tearing with RenderDoc (prevents crashing) +#endif + ) + AllowTearing = true; + } + // Get flags and device type base on current configuration uint32 flags = D3D11_CREATE_DEVICE_BGRA_SUPPORT; #if GPU_ENABLE_DIAGNOSTICS @@ -276,18 +290,7 @@ bool GPUDeviceDX11::Init() // Create DirectX device D3D_FEATURE_LEVEL createdFeatureLevel = static_cast(0); auto targetFeatureLevel = GetD3DFeatureLevel(); - VALIDATE_DIRECTX_RESULT(D3D11CreateDevice( - adapter, - D3D_DRIVER_TYPE_UNKNOWN, - NULL, - flags, - &targetFeatureLevel, - 1, - D3D11_SDK_VERSION, - &_device, - &createdFeatureLevel, - &_imContext - )); + VALIDATE_DIRECTX_RESULT(D3D11CreateDevice(adapter, D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, &targetFeatureLevel, 1, D3D11_SDK_VERSION, &_device, &createdFeatureLevel, &_imContext)); // Validate result ASSERT(_device); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h index de0132ea3..ec2ba0177 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUDeviceDX11.h @@ -50,6 +50,10 @@ public: GPUDeviceDX11(IDXGIFactory* dxgiFactory, GPUAdapterDX* adapter); ~GPUDeviceDX11(); +public: + + bool AllowTearing = false; + public: // Gets DX11 device diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp index 56fcfcc77..2986a15fd 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.cpp @@ -17,6 +17,8 @@ GPUSwapChainDX11::GPUSwapChainDX11(GPUDeviceDX11* device, Window* window) #endif , _swapChain(nullptr) , _backBuffer(nullptr) + , _allowTearing(false) + , _isFullscreen(false) { ASSERT(_windowHandle); _window = window; @@ -108,6 +110,18 @@ void GPUSwapChainDX11::SetFullscreen(bool isFullscreen) { LOG(Warning, "Cannot change fullscreen mode for '{0}' to {1}.", ToString(), isFullscreen); } + + _isFullscreen = isFullscreen; + + // Buffers must be resized in flip presentation model + if (swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL || + swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) + { + const int32 width = _width; + const int32 height = _height; + _width = _height = 0; + Resize(width, height); + } } #else LOG(Info, "Cannot change fullscreen mode on this platform"); @@ -123,7 +137,14 @@ void GPUSwapChainDX11::Present(bool vsync) { // Present frame ASSERT(_swapChain); - const HRESULT result = _swapChain->Present(vsync ? 1 : 0, 0); + UINT presentFlags = 0; +#if PLATFORM_WINDOWS + if (!vsync && !_isFullscreen && _allowTearing) + { + presentFlags |= DXGI_PRESENT_ALLOW_TEARING; + } +#endif + const HRESULT result = _swapChain->Present(vsync ? 1 : 0, presentFlags); LOG_DIRECTX_RESULT(result); // Base @@ -140,6 +161,9 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height) _device->WaitForGPU(); GPUDeviceLock lock(_device); +#if PLATFORM_WINDOWS + _allowTearing = _device->AllowTearing; +#endif _format = GPU_BACK_BUFFER_PIXEL_FORMAT; #if PLATFORM_WINDOWS @@ -177,6 +201,11 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height) swapChainDesc.Windowed = TRUE; swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; swapChainDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; + if (_allowTearing) + { + swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; + swapChainDesc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; + } #else swapChainDesc.Width = width; swapChainDesc.Height = height; @@ -202,7 +231,7 @@ bool GPUSwapChainDX11::Resize(int32 width, int32 height) ASSERT(_swapChain); // Disable DXGI changes to the window - VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, 0)); + VALIDATE_DIRECTX_RESULT(dxgi->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER)); #else auto dxgiFactory = (IDXGIFactory2*)_device->GetDXGIFactory(); VALIDATE_DIRECTX_RESULT(dxgiFactory->CreateSwapChainForCoreWindow(_device->GetDevice(), static_cast(_windowHandle), &swapChainDesc, nullptr, &_swapChain)); diff --git a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.h b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.h index f0a785930..35688affc 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.h +++ b/Source/Engine/GraphicsDevice/DirectX/DX11/GPUSwapChainDX11.h @@ -23,6 +23,7 @@ private: #if PLATFORM_WINDOWS HWND _windowHandle; IDXGISwapChain* _swapChain; + bool _allowTearing, _isFullscreen; #else IUnknown* _windowHandle; IDXGISwapChain1* _swapChain; diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp index 5aae0febf..3483b5e4e 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUDeviceDX12.cpp @@ -264,17 +264,19 @@ bool GPUDeviceDX12::Init() return true; } UpdateOutputs(adapter); + + ComPtr factory5; + _factoryDXGI->QueryInterface(IID_PPV_ARGS(&factory5)); + if (factory5) { - ComPtr factory5; - _factoryDXGI->QueryInterface(IID_PPV_ARGS(&factory5)); - if (factory5) - { - BOOL allowTearing; - if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))) && allowTearing) - { - AllowTearing = true; - } - } + BOOL allowTearing; + if (SUCCEEDED(factory5->CheckFeatureSupport(DXGI_FEATURE_PRESENT_ALLOW_TEARING, &allowTearing, sizeof(allowTearing))) + && allowTearing +#if PLATFORM_WINDOWS + && GetModuleHandleA("renderdoc.dll") == nullptr // Disable tearing with RenderDoc (prevents crashing) +#endif + ) + AllowTearing = true; } // Create DirectX device diff --git a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp index f4784f479..e7e976987 100644 --- a/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp +++ b/Source/Engine/GraphicsDevice/DirectX/DX12/GPUSwapChainDX12.cpp @@ -51,6 +51,8 @@ GPUSwapChainDX12::GPUSwapChainDX12(GPUDeviceDX12* device, Window* window) , _windowHandle(static_cast(window->GetNativePtr())) , _swapChain(nullptr) , _currentFrameIndex(0) + , _allowTearing(false) + , _isFullscreen(false) { ASSERT(_windowHandle); _window = window; @@ -135,6 +137,16 @@ void GPUSwapChainDX12::SetFullscreen(bool isFullscreen) } _isFullscreen = isFullscreen; + + // Buffers must be resized in flip presentation model + if (swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL || + swapChainDesc.SwapEffect == DXGI_SWAP_EFFECT_FLIP_DISCARD) + { + const int32 width = _width; + const int32 height = _height; + _width = _height = 0; + Resize(width, height); + } } #else LOG(Info, "Cannot change fullscreen mode on this platform"); @@ -217,7 +229,7 @@ bool GPUSwapChainDX12::Resize(int32 width, int32 height) _backBuffers.Resize(swapChainDesc.BufferCount); // Disable DXGI changes to the window - dxgiFactory->MakeWindowAssociation(_windowHandle, 0); + VALIDATE_DIRECTX_RESULT(dxgiFactory->MakeWindowAssociation(_windowHandle, DXGI_MWA_NO_ALT_ENTER)); } else { diff --git a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h index ca4dae608..7cf4be599 100644 --- a/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h +++ b/Source/Engine/GraphicsDevice/DirectX/IncludeDirectXHeaders.h @@ -39,6 +39,7 @@ typedef IGraphicsUnknown IDXGISwapChain3; #include #include #include +#include #endif #if GRAPHICS_API_DIRECTX12 #include diff --git a/Source/Engine/Level/Actor.cpp b/Source/Engine/Level/Actor.cpp index 72c35da56..a80c3ceed 100644 --- a/Source/Engine/Level/Actor.cpp +++ b/Source/Engine/Level/Actor.cpp @@ -1358,7 +1358,7 @@ bool Actor::HasActorInChildren(Actor* a) const bool Actor::IntersectsItself(const Ray& ray, float& distance, Vector3& normal) { - return GetBox().Intersects(ray, distance, normal); + return _box.Intersects(ray, distance, normal); } Actor* Actor::Intersects(const Ray& ray, float& distance, Vector3& normal) diff --git a/Source/Engine/Level/Actors/AnimatedModel.cpp b/Source/Engine/Level/Actors/AnimatedModel.cpp index e2d5a5668..3ddfdd3a1 100644 --- a/Source/Engine/Level/Actors/AnimatedModel.cpp +++ b/Source/Engine/Level/Actors/AnimatedModel.cpp @@ -76,7 +76,8 @@ void AnimatedModel::SetupSkinningData() void AnimatedModel::PreInitSkinningData() { - ASSERT(SkinnedModel && SkinnedModel->IsLoaded()); + if (!SkinnedModel || !SkinnedModel->IsLoaded()) + return; ScopeLock lock(SkinnedModel->Locker); diff --git a/Source/Engine/Physics/Actors/PhysicsActor.cpp b/Source/Engine/Physics/Actors/PhysicsActor.cpp deleted file mode 100644 index 120d83bc4..000000000 --- a/Source/Engine/Physics/Actors/PhysicsActor.cpp +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. - -#include "PhysicsActor.h" -#include "../PhysicsBackend.h" - -PhysicsActor::PhysicsActor(const SpawnParams& params) - : Actor(params) - , _cachedScale(1.0f) - , _isUpdatingTransform(false) -{ -} - -void PhysicsActor::OnActiveTransformChanged() -{ - // Change actor transform (but with locking) - ASSERT(!_isUpdatingTransform); - _isUpdatingTransform = true; - Transform transform; - PhysicsBackend::GetRigidActorPose(GetPhysicsActor(), transform.Translation, transform.Orientation); - transform.Scale = _transform.Scale; - if (_parent) - { - _parent->GetTransform().WorldToLocal(transform, _localTransform); - } - else - { - _localTransform = transform; - } - OnTransformChanged(); - _isUpdatingTransform = false; -} - -void PhysicsActor::OnTransformChanged() -{ - // Base - Actor::OnTransformChanged(); - - UpdateBounds(); -} - -void PhysicsActor::UpdateBounds() -{ - void* actor = GetPhysicsActor(); - if (actor) - PhysicsBackend::GetActorBounds(actor, _box); - else - _box = BoundingBox(_transform.Translation); - BoundingSphere::FromBox(_box, _sphere); -} - -bool PhysicsActor::IntersectsItself(const Ray& ray, float& distance, Vector3& normal) -{ - return _box.Intersects(ray, distance, normal); -} diff --git a/Source/Engine/Physics/Actors/PhysicsActor.h b/Source/Engine/Physics/Actors/PhysicsActor.h deleted file mode 100644 index 961c07eee..000000000 --- a/Source/Engine/Physics/Actors/PhysicsActor.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. - -#pragma once - -#include "Engine/Level/Actor.h" -#include "Engine/Physics/Types.h" -#include "IPhysicsActor.h" - -/// -/// A base class for all physical actors. -/// -/// -API_CLASS(Abstract) class FLAXENGINE_API PhysicsActor : public Actor, public IPhysicsActor -{ -DECLARE_SCENE_OBJECT_ABSTRACT(PhysicsActor); -protected: - - Vector3 _cachedScale; - bool _isUpdatingTransform; - -public: - - /// - /// Updates the bounding box. - /// - void UpdateBounds(); - -public: - - // [Actor] - bool IntersectsItself(const Ray& ray, float& distance, Vector3& normal) override; - - // [IPhysicsActor] - void OnActiveTransformChanged() override; - -protected: - - // [Actor] - void OnTransformChanged() override; -}; diff --git a/Source/Engine/Physics/Actors/RigidBody.cpp b/Source/Engine/Physics/Actors/RigidBody.cpp index 193422c0c..26512fb61 100644 --- a/Source/Engine/Physics/Actors/RigidBody.cpp +++ b/Source/Engine/Physics/Actors/RigidBody.cpp @@ -8,8 +8,9 @@ #include "Engine/Serialization/Serialization.h" RigidBody::RigidBody(const SpawnParams& params) - : PhysicsActor(params) + : Actor(params) , _actor(nullptr) + , _cachedScale(1.0f) , _mass(1.0f) , _linearDamping(0.01f) , _angularDamping(0.05f) @@ -24,6 +25,7 @@ RigidBody::RigidBody(const SpawnParams& params) , _startAwake(true) , _updateMassWhenScaleChanges(false) , _overrideMass(false) + , _isUpdatingTransform(false) { } @@ -224,13 +226,13 @@ bool RigidBody::IsSleeping() const void RigidBody::Sleep() const { if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy()) - PhysicsBackend::GetRigidActorSleep(_actor); + PhysicsBackend::RigidDynamicActorSleep(_actor); } void RigidBody::WakeUp() const { if (_actor && GetEnableSimulation() && !GetIsKinematic() && IsActiveInHierarchy()) - PhysicsBackend::GetRigidDynamicActorWakeUp(_actor); + PhysicsBackend::RigidDynamicActorWakeUp(_actor); } void RigidBody::UpdateMass() @@ -323,6 +325,16 @@ void RigidBody::OnColliderChanged(Collider* c) // WakeUp(); } +void RigidBody::UpdateBounds() +{ + void* actor = GetPhysicsActor(); + if (actor && PhysicsBackend::GetRigidActorShapesCount(actor) != 0) + PhysicsBackend::GetActorBounds(actor, _box); + else + _box = BoundingBox(_transform.Translation); + BoundingSphere::FromBox(_box, _sphere); +} + void RigidBody::UpdateScale() { const Vector3 scale = GetScale(); @@ -339,7 +351,7 @@ void RigidBody::UpdateScale() void RigidBody::Serialize(SerializeStream& stream, const void* otherObj) { // Base - PhysicsActor::Serialize(stream, otherObj); + Actor::Serialize(stream, otherObj); SERIALIZE_GET_OTHER_OBJ(RigidBody); @@ -364,7 +376,7 @@ void RigidBody::Serialize(SerializeStream& stream, const void* otherObj) void RigidBody::Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) { // Base - PhysicsActor::Deserialize(stream, modifier); + Actor::Deserialize(stream, modifier); DESERIALIZE_BIT_MEMBER(OverrideMass, _overrideMass); DESERIALIZE_MEMBER(Mass, _mass); @@ -389,6 +401,26 @@ void* RigidBody::GetPhysicsActor() const return _actor; } +void RigidBody::OnActiveTransformChanged() +{ + // Change actor transform (but with locking) + ASSERT(!_isUpdatingTransform); + _isUpdatingTransform = true; + Transform transform; + PhysicsBackend::GetRigidActorPose(GetPhysicsActor(), transform.Translation, transform.Orientation); + transform.Scale = _transform.Scale; + if (_parent) + { + _parent->GetTransform().WorldToLocal(transform, _localTransform); + } + else + { + _localTransform = transform; + } + OnTransformChanged(); + _isUpdatingTransform = false; +} + void RigidBody::BeginPlay(SceneBeginData* data) { // Create rigid body @@ -441,13 +473,13 @@ void RigidBody::BeginPlay(SceneBeginData* data) UpdateBounds(); // Base - PhysicsActor::BeginPlay(data); + Actor::BeginPlay(data); } void RigidBody::EndPlay() { // Base - PhysicsActor::EndPlay(); + Actor::EndPlay(); if (_actor) { @@ -462,7 +494,7 @@ void RigidBody::EndPlay() void RigidBody::OnActiveInTreeChanged() { // Base - PhysicsActor::OnActiveInTreeChanged(); + Actor::OnActiveInTreeChanged(); if (_actor) { @@ -480,23 +512,18 @@ void RigidBody::OnActiveInTreeChanged() void RigidBody::OnTransformChanged() { + // Base + Actor::OnTransformChanged(); + // Update physics is not during physics state synchronization if (!_isUpdatingTransform && _actor) { - // Base (skip PhysicsActor call to optimize) - Actor::OnTransformChanged(); - const bool kinematic = GetIsKinematic() && GetEnableSimulation(); PhysicsBackend::SetRigidActorPose(_actor, _transform.Translation, _transform.Orientation, kinematic, true); - UpdateScale(); - UpdateBounds(); - } - else - { - // Base - PhysicsActor::OnTransformChanged(); } + + UpdateBounds(); } void RigidBody::OnPhysicsSceneChanged(PhysicsScene* previous) diff --git a/Source/Engine/Physics/Actors/RigidBody.h b/Source/Engine/Physics/Actors/RigidBody.h index 557ac55be..bbe30fe08 100644 --- a/Source/Engine/Physics/Actors/RigidBody.h +++ b/Source/Engine/Physics/Actors/RigidBody.h @@ -2,7 +2,9 @@ #pragma once -#include "PhysicsActor.h" +#include "Engine/Level/Actor.h" +#include "Engine/Physics/Types.h" +#include "Engine/Physics/Actors/IPhysicsActor.h" #include "Engine/Physics/Collisions.h" class PhysicsColliderActor; @@ -11,8 +13,8 @@ class Collider; /// /// Physics simulation driven object. /// -/// -API_CLASS() class FLAXENGINE_API RigidBody : public PhysicsActor +/// +API_CLASS() class FLAXENGINE_API RigidBody : public Actor, public IPhysicsActor { DECLARE_SCENE_OBJECT(RigidBody); protected: @@ -35,6 +37,7 @@ protected: int32 _startAwake : 1; int32 _updateMassWhenScaleChanges : 1; int32 _overrideMass : 1; + int32 _isUpdatingTransform : 1; public: @@ -537,7 +540,10 @@ public: // Called when collider gets detached from this rigidbody or activated/deactivated. Used to update rigidbody mass. virtual void OnColliderChanged(Collider* c); -protected: + /// + /// Updates the bounding box. + /// + void UpdateBounds(); /// /// Updates the rigidbody scale dependent properties like mass (may be modified when actor transformation changes). @@ -546,14 +552,17 @@ protected: public: - // [PhysicsActor] + // [Actor] void Serialize(SerializeStream& stream, const void* otherObj) override; void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) override; + + // [IPhysicsActor] void* GetPhysicsActor() const override; + void OnActiveTransformChanged() override; protected: - // [PhysicsActor] + // [Actor] void BeginPlay(SceneBeginData* data) override; void EndPlay() override; void OnActiveInTreeChanged() override; diff --git a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp index c1a08210d..256e48d5f 100644 --- a/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp +++ b/Source/Engine/Physics/PhysX/PhysicsBackendPhysX.cpp @@ -1607,6 +1607,12 @@ void PhysicsBackend::GetActorBounds(void* actor, BoundingBox& bounds) bounds = P2C(actorPhysX->getWorldBounds(boundsScale)); } +int32 PhysicsBackend::GetRigidActorShapesCount(void* actor) +{ + auto actorPhysX = (PxRigidActor*)actor; + return actorPhysX->getNbShapes(); +} + void* PhysicsBackend::CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation) { const PxTransform trans(C2P(position), C2P(orientation)); @@ -1749,13 +1755,13 @@ bool PhysicsBackend::GetRigidDynamicActorIsSleeping(void* actor) return actorPhysX->isSleeping(); } -void PhysicsBackend::GetRigidActorSleep(void* actor) +void PhysicsBackend::RigidDynamicActorSleep(void* actor) { auto actorPhysX = (PxRigidDynamic*)actor; actorPhysX->putToSleep(); } -void PhysicsBackend::GetRigidDynamicActorWakeUp(void* actor) +void PhysicsBackend::RigidDynamicActorWakeUp(void* actor) { auto actorPhysX = (PxRigidDynamic*)actor; actorPhysX->wakeUp(); diff --git a/Source/Engine/Physics/PhysicsBackend.h b/Source/Engine/Physics/PhysicsBackend.h index 4c50e9ea0..980387bcb 100644 --- a/Source/Engine/Physics/PhysicsBackend.h +++ b/Source/Engine/Physics/PhysicsBackend.h @@ -131,6 +131,7 @@ public: static ActorFlags GetActorFlags(void* actor); static void SetActorFlags(void* actor, ActorFlags value); static void GetActorBounds(void* actor, BoundingBox& bounds); + static int32 GetRigidActorShapesCount(void* actor); static void* CreateRigidDynamicActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); static void* CreateRigidStaticActor(IPhysicsActor* actor, const Vector3& position, const Quaternion& orientation); static RigidDynamicFlags GetRigidDynamicActorFlags(void* actor); @@ -148,8 +149,8 @@ public: static Vector3 GetRigidDynamicActorCenterOfMass(void* actor); static void SetRigidDynamicActorCenterOfMassOffset(void* actor, const Vector3& value); static bool GetRigidDynamicActorIsSleeping(void* actor); - static void GetRigidActorSleep(void* actor); - static void GetRigidDynamicActorWakeUp(void* actor); + static void RigidDynamicActorSleep(void* actor); + static void RigidDynamicActorWakeUp(void* actor); static float GetRigidDynamicActorSleepThreshold(void* actor); static void SetRigidDynamicActorSleepThreshold(void* actor, float value); static float GetRigidDynamicActorMaxDepenetrationVelocity(void* actor); diff --git a/Source/Engine/Platform/Windows/WindowsWindow.cpp b/Source/Engine/Platform/Windows/WindowsWindow.cpp index 50f092407..cb1617219 100644 --- a/Source/Engine/Platform/Windows/WindowsWindow.cpp +++ b/Source/Engine/Platform/Windows/WindowsWindow.cpp @@ -1031,6 +1031,10 @@ LRESULT WindowsWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) // In this case, we don't resize yet -- we wait until the user stops dragging, and a WM_EXITSIZEMOVE message comes. UpdateRegion(); } + else if (_isSwitchingFullScreen) + { + // Ignored + } else { // This WM_SIZE come from resizing the window via an API like SetWindowPos() so resize @@ -1090,6 +1094,12 @@ LRESULT WindowsWindow::WndProc(UINT msg, WPARAM wParam, LPARAM lParam) Close(ClosingReason::User); return 0; } + if (wParam == VK_RETURN) + { + LOG(Info, "Alt+Enter pressed"); + SetIsFullscreen(!IsFullscreen()); + return 0; + } break; case WM_POWERBROADCAST: switch (wParam) diff --git a/Source/Engine/Render2D/Render2D.cpp b/Source/Engine/Render2D/Render2D.cpp index 779746d8d..8c6760ba8 100644 --- a/Source/Engine/Render2D/Render2D.cpp +++ b/Source/Engine/Render2D/Render2D.cpp @@ -1331,7 +1331,7 @@ void Render2D::DrawText(Font* font, const StringView& text, const Color& color, { // Calculate character size and atlas coordinates const float x = pointer.X + entry.OffsetX * scale; - const float y = pointer.Y + (font->GetHeight() + font->GetDescender() - entry.OffsetY) * scale; + const float y = pointer.Y - entry.OffsetY * scale + Math::Ceil((font->GetHeight() + font->GetDescender()) * scale); Rectangle charRect(x, y, entry.UVSize.X * scale, entry.UVSize.Y * scale); charRect.Offset(layout.Bounds.Location); diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 3cb7d5f0a..7738fec45 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -541,7 +541,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext) renderContext.List->RunMaterialPostFxPass(context, renderContext, MaterialPostFxLocation::AfterAntiAliasingPass, frameBuffer, tempBuffer); // PostFx -> (up-scaling) -> Back Buffer - if (Math::IsOne(task->RenderingPercentage)) + if (task->RenderingPercentage >= 1.0f) { PROFILE_GPU("Copy frame"); context->SetRenderTarget(task->GetOutputView()); diff --git a/Source/Engine/Scripting/BinaryModule.h b/Source/Engine/Scripting/BinaryModule.h index 5ea3713c5..73144c449 100644 --- a/Source/Engine/Scripting/BinaryModule.h +++ b/Source/Engine/Scripting/BinaryModule.h @@ -260,7 +260,7 @@ public: private: - int32 _firstManagedTypeIndex; + int32 _firstManagedTypeIndex = 0; Array _managedMemoryBlocks; public: diff --git a/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp b/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp index 8471f02cb..996bbb420 100644 --- a/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MAssembly.cpp @@ -352,6 +352,7 @@ bool MAssembly::LoadWithImage(const String& assemblyPath) } } + // TODO: load pdbs for custom third-party libs referenced by game assemblies for debugging #if 0 // Hack to load debug information for Newtonsoft.Json (enable it to debug C# code of json lib) if (assemblyPath.EndsWith(TEXT("FlaxEngine.CSharp.dll"))) diff --git a/Source/Engine/Scripting/ManagedCLR/MCore.cpp b/Source/Engine/Scripting/ManagedCLR/MCore.cpp index 91f12cfb0..f7b46e5cc 100644 --- a/Source/Engine/Scripting/ManagedCLR/MCore.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MCore.cpp @@ -2,7 +2,6 @@ #include "MCore.h" #include "MDomain.h" -#include "MClass.h" #include "Engine/Core/Log.h" #include "Engine/Core/Types/String.h" #include "Engine/Core/Types/DateTime.h" @@ -353,6 +352,9 @@ bool MCore::LoadEngine() PROFILE_CPU(); ASSERT(Globals::MonoPath.IsANSI()); + // Debugging Mono GC + //Platform::SetEnvironmentVariable(TEXT("MONO_GC_DEBUG"), TEXT("6:gc-log.txt,check-remset-consistency,nursery-canaries")); + #if 0 // Override memory allocation callback // TODO: use ENABLE_OVERRIDABLE_ALLOCATORS when building Mono to support memory callbacks or use counters for memory profiling diff --git a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp index 3b46e4f36..aa5d1a6a1 100644 --- a/Source/Engine/Scripting/ManagedCLR/MUtils.cpp +++ b/Source/Engine/Scripting/ManagedCLR/MUtils.cpp @@ -114,7 +114,7 @@ MonoString* MUtils::ToString(const String& str) MonoString* MUtils::ToString(const String& str, MonoDomain* domain) { if (str.IsEmpty()) - return mono_string_empty(mono_domain_get()); + return mono_string_empty(domain); return mono_string_new_utf16(domain, (const mono_unichar2*)*str, str.Length()); } diff --git a/Source/Engine/Scripting/ManagedSerialization.cpp b/Source/Engine/Scripting/ManagedSerialization.cpp index 97560701c..1fa799d56 100644 --- a/Source/Engine/Scripting/ManagedSerialization.cpp +++ b/Source/Engine/Scripting/ManagedSerialization.cpp @@ -10,7 +10,7 @@ #include "ManagedCLR/MMethod.h" #include -void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MonoObject* object) +void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, MObject* object) { if (!object) { @@ -47,7 +47,7 @@ void ManagedSerialization::Serialize(ISerializable::SerializeStream& stream, Mon mono_free(invokeResultChars); } -void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream, MonoObject* object, MonoObject* other) +void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream, MObject* object, MObject* other) { if (!object || !other) { @@ -85,7 +85,7 @@ void ManagedSerialization::SerializeDiff(ISerializable::SerializeStream& stream, mono_free(invokeResultChars); } -void ManagedSerialization::Deserialize(ISerializable::DeserializeStream& stream, MonoObject* object) +void ManagedSerialization::Deserialize(ISerializable::DeserializeStream& stream, MObject* object) { if (!object) return; @@ -98,7 +98,7 @@ void ManagedSerialization::Deserialize(ISerializable::DeserializeStream& stream, Deserialize(StringAnsiView(buffer.GetString(), (int32)buffer.GetSize()), object); } -void ManagedSerialization::Deserialize(const StringAnsiView& data, MonoObject* object) +void ManagedSerialization::Deserialize(const StringAnsiView& data, MObject* object) { const char* str = data.Get(); const int32 len = data.Length(); diff --git a/Source/Engine/Scripting/ManagedSerialization.h b/Source/Engine/Scripting/ManagedSerialization.h index fdcccdcd1..10495dd36 100644 --- a/Source/Engine/Scripting/ManagedSerialization.h +++ b/Source/Engine/Scripting/ManagedSerialization.h @@ -18,7 +18,7 @@ public: /// /// The output stream. /// The object to serialize. - static void Serialize(ISerializable::SerializeStream& stream, MonoObject* object); + static void Serialize(ISerializable::SerializeStream& stream, MObject* object); /// /// Serializes managed object difference to JSON. @@ -26,20 +26,20 @@ public: /// The output stream. /// The object to serialize. /// The reference object to serialize diff compared to it. - static void SerializeDiff(ISerializable::SerializeStream& stream, MonoObject* object, MonoObject* other); + static void SerializeDiff(ISerializable::SerializeStream& stream, MObject* object, MObject* other); /// /// Deserializes managed object from the JSON. /// /// The input stream. /// The object to deserialize. - static void Deserialize(ISerializable::DeserializeStream& stream, MonoObject* object); + static void Deserialize(ISerializable::DeserializeStream& stream, MObject* object); /// /// Deserializes managed object from the JSON. /// /// The input data. /// The object to deserialize. - static void Deserialize(const StringAnsiView& data, MonoObject* object); + static void Deserialize(const StringAnsiView& data, MObject* object); #endif }; diff --git a/Source/Engine/Scripting/Object.cs b/Source/Engine/Scripting/Object.cs index 51001a86a..b86ed00d8 100644 --- a/Source/Engine/Scripting/Object.cs +++ b/Source/Engine/Scripting/Object.cs @@ -47,7 +47,7 @@ namespace FlaxEngine { Internal_ManagedInstanceCreated(this); if (__unmanagedPtr == IntPtr.Zero) - throw new FlaxException($"Failed to create native instance for object of type {GetType().FullName} (assembly: {GetType().Assembly.FullName})."); + throw new Exception($"Failed to create native instance for object of type {GetType().FullName} (assembly: {GetType().Assembly.FullName})."); } } diff --git a/Source/Engine/Scripting/Scripting.cs b/Source/Engine/Scripting/Scripting.cs index 5c7689fdb..6eff982d9 100644 --- a/Source/Engine/Scripting/Scripting.cs +++ b/Source/Engine/Scripting/Scripting.cs @@ -170,8 +170,12 @@ namespace FlaxEngine private static void OnLocalizationChanged() { var currentThread = Thread.CurrentThread; - currentThread.CurrentUICulture = Localization.CurrentLanguage; - currentThread.CurrentCulture = Localization.CurrentCulture; + var language = Localization.CurrentLanguage; + if (language != null) + currentThread.CurrentUICulture = language; + var culture = Localization.CurrentCulture; + if (culture != null) + currentThread.CurrentCulture = culture; } /// diff --git a/Source/Engine/Serialization/JsonSerializer.cs b/Source/Engine/Serialization/JsonSerializer.cs index 2099bc387..29a5951f9 100644 --- a/Source/Engine/Serialization/JsonSerializer.cs +++ b/Source/Engine/Serialization/JsonSerializer.cs @@ -188,7 +188,7 @@ namespace FlaxEngine.Json while (reader.Read()) { if (reader.TokenType != JsonToken.Comment) - throw new FlaxException("Additional text found in JSON string after finishing deserializing object."); + throw new Exception("Additional text found in JSON string after finishing deserializing object."); } } } @@ -226,7 +226,7 @@ namespace FlaxEngine.Json while (reader.Read()) { if (reader.TokenType != JsonToken.Comment) - throw new FlaxException("Additional text found in JSON string after finishing deserializing object."); + throw new Exception("Additional text found in JSON string after finishing deserializing object."); } } @@ -254,7 +254,7 @@ namespace FlaxEngine.Json while (reader.Read()) { if (reader.TokenType != JsonToken.Comment) - throw new FlaxException("Additional text found in JSON string after finishing deserializing object."); + throw new Exception("Additional text found in JSON string after finishing deserializing object."); } } @@ -297,7 +297,7 @@ namespace FlaxEngine.Json while (jsonReader.Read()) { if (jsonReader.TokenType != JsonToken.Comment) - throw new FlaxException("Additional text found in JSON string after finishing deserializing object."); + throw new Exception("Additional text found in JSON string after finishing deserializing object."); } } diff --git a/Source/Engine/Utilities/Utils.cs b/Source/Engine/Utilities/Utils.cs index 313fa276a..cc647a4fe 100644 --- a/Source/Engine/Utilities/Utils.cs +++ b/Source/Engine/Utilities/Utils.cs @@ -357,6 +357,14 @@ namespace FlaxEngine return new Matrix(stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle(), stream.ReadSingle()); } + internal static byte[] ReadJsonBytes(this BinaryReader stream) + { + // ReadStream::ReadJson + var engineBuild = stream.ReadInt32(); + var size = stream.ReadInt32(); + return stream.ReadBytes(size); + } + /// /// Deserializes object from Json by reading it as a raw data (ver+length+bytes). /// @@ -569,6 +577,19 @@ namespace FlaxEngine stream.Write(value.M44); } + internal static void WriteJsonBytes(this BinaryWriter stream, byte[] bytes) + { + // WriteStream::WriteJson + stream.Write(Globals.EngineBuildNumber); + if (bytes != null) + { + stream.Write(bytes.Length); + stream.Write(bytes); + } + else + stream.Write(0); + } + /// /// Serializes object to Json and writes it as a raw data (ver+length+bytes). /// diff --git a/Source/Engine/Visject/ShaderGraph.cpp b/Source/Engine/Visject/ShaderGraph.cpp index 11adc31cd..e2f1472d3 100644 --- a/Source/Engine/Visject/ShaderGraph.cpp +++ b/Source/Engine/Visject/ShaderGraph.cpp @@ -156,6 +156,10 @@ void ShaderGenerator::ProcessGroupMath(Box* box, Node* node, Value& value) Box* b2 = node->GetBox(1); Value v1 = tryGetValue(b1, 0, Value::Zero); Value v2 = tryGetValue(b2, 1, Value::Zero); + if (b1->HasConnection()) + v2 = v2.Cast(v1.Type); + else + v1 = v1.Cast(v2.Type); Char op = '?'; switch (node->TypeID) { diff --git a/Source/Engine/Visject/VisjectGraph.cpp b/Source/Engine/Visject/VisjectGraph.cpp index 658121b20..9d706cca0 100644 --- a/Source/Engine/Visject/VisjectGraph.cpp +++ b/Source/Engine/Visject/VisjectGraph.cpp @@ -154,8 +154,13 @@ void VisjectExecutor::ProcessGroupMath(Box* box, Node* node, Value& value) case 40: case 41: { - Value v1 = tryGetValue(node->GetBox(0), 0, Value::Zero); - Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero).Cast(v1.Type); + auto b1 = node->GetBox(0); + Value v1 = tryGetValue(b1, 0, Value::Zero); + Value v2 = tryGetValue(node->GetBox(1), 1, Value::Zero); + if (b1->HasConnection()) + v2 = v2.Cast(v1.Type); + else + v1 = v1.Cast(v2.Type); GraphUtilities::ApplySomeMathHere(node->TypeID, value, v1, v2); break; } diff --git a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs index c549ae84b..1637524c2 100644 --- a/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs +++ b/Source/Tools/Flax.Build/Build/DotNet/Builder.DotNet.cs @@ -160,7 +160,7 @@ namespace Flax.Build // Prefer installed Roslyn C# compiler over Mono one monoPath = null; - cscPath = Path.Combine(Path.GetDirectoryName(Deploy.VCEnvironment.MSBuildPath), "Roslyn", "csc.exe"); + cscPath = Path.Combine(Path.GetDirectoryName(VCEnvironment.MSBuildPath), "Roslyn", "csc.exe"); if (!File.Exists(cscPath)) { diff --git a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs index 98c352829..0ca955324 100644 --- a/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs +++ b/Source/Tools/Flax.Build/Deploy/VCEnvironment.cs @@ -1,6 +1,7 @@ // Copyright (c) 2012-2020 Flax Engine. All rights reserved. using System; +using System.Collections.Generic; using System.IO; using System.Linq; using Flax.Build; @@ -219,7 +220,8 @@ namespace Flax.Deploy /// Path to the solution file /// Configuration to build. /// Platform to build. - public static void BuildSolution(string solutionFile, string buildConfig, string buildPlatform) + /// Custom build properties mapping (property=value). + public static void BuildSolution(string solutionFile, string buildConfig, string buildPlatform, Dictionary props = null) { var msBuild = MSBuildPath; if (string.IsNullOrEmpty(msBuild)) @@ -233,6 +235,11 @@ namespace Flax.Deploy } string cmdLine = string.Format("\"{0}\" /m /t:Build /p:Configuration=\"{1}\" /p:Platform=\"{2}\" {3} /nologo", solutionFile, buildConfig, buildPlatform, Verbosity); + if (props != null) + { + foreach (var e in props) + cmdLine += string.Format(" /p:{0}={1}", e.Key, e.Value); + } int result = Utilities.Run(msBuild, cmdLine); if (result != 0) { diff --git a/Source/Tools/Flax.Build/Deps/Dependency.cs b/Source/Tools/Flax.Build/Deps/Dependency.cs index 4a801b13c..ed4d4731a 100644 --- a/Source/Tools/Flax.Build/Deps/Dependency.cs +++ b/Source/Tools/Flax.Build/Deps/Dependency.cs @@ -99,6 +99,18 @@ namespace Flax.Deps } } + /// + /// Clones the directory. + /// + /// The source folder path. + /// The destination folder path. + public static void CloneDirectory(string src, string dst) + { + if (Directory.Exists(dst)) + Utilities.DirectoryDelete(dst); + Utilities.DirectoryCopy(src, dst); + } + /// /// Clones the git repository from the remote url (full repository). /// @@ -275,30 +287,76 @@ namespace Flax.Deps /// /// The path. /// The workspace folder. - /// Custom environment variables to pass to the child process. - public static void RunCygwin(string path, string workspace = null, Dictionary envVars = null) + public static void RunCygwin(string path, string workspace = null) + { + RunBash(path, string.Empty, workspace); + } + + /// + /// Runs the bash script (executes natively on Unix platforms, uses Cygwin on Windows). + /// + /// The script or command path. + /// The arguments. + /// The workspace folder. + /// Custom environment variables to pass to the child process. + public static void RunBash(string path, string args = null, string workspace = null, Dictionary envVars = null) { - string app; switch (BuildPlatform) { case TargetPlatform.Windows: { + // Find Cygwin var cygwinFolder = Environment.GetEnvironmentVariable("CYGWIN"); if (string.IsNullOrEmpty(cygwinFolder) || !Directory.Exists(cygwinFolder)) { cygwinFolder = "C:\\cygwin"; if (!Directory.Exists(cygwinFolder)) - throw new Exception("Missing Cygwin. Install Cygwin64 to C:\\cygwin or set CYGWIN env variable to install location folder."); + { + cygwinFolder = "C:\\cygwin64"; + if (!Directory.Exists(cygwinFolder)) + throw new Exception("Missing Cygwin. Install Cygwin64 to C:\\cygwin or set CYGWIN env variable to install location folder."); + } + } + var cygwinBinFolder = Path.Combine(cygwinFolder, "bin"); + + // Ensure that Cygwin binaries folder is in a PATH + string envPath = null; + envVars?.TryGetValue("PATH", out envPath); + if (envPath == null || envPath.IndexOf(cygwinBinFolder, StringComparison.OrdinalIgnoreCase) == -1) + { + if (envVars == null) + envVars = new Dictionary(); + envVars["PATH"] = cygwinBinFolder; + if (envPath != null) + envVars["PATH"] += ";" + envPath; + } + + // Get the executable file path + if (path.EndsWith(".sh", StringComparison.OrdinalIgnoreCase)) + { + // Bash script + if (args == null) + args = path.Replace('\\', '/'); + else + args = path.Replace('\\', '/') + " " + args; + path = Path.Combine(cygwinBinFolder, "bash.exe"); + } + else if (File.Exists(Path.Combine(cygwinBinFolder, path + ".exe"))) + { + // Tool (eg. make) + path = Path.Combine(cygwinBinFolder, path + ".exe"); + } + else + { + throw new Exception("Cannot execute command " + path + " with args " + args); } - app = Path.Combine(cygwinFolder, "bin\\bash.exe"); break; } case TargetPlatform.Linux: - app = "bash"; - break; + case TargetPlatform.Mac: break; default: throw new InvalidPlatformException(BuildPlatform); } - Utilities.Run(app, path, null, workspace, Utilities.RunOptions.None, envVars); + Utilities.Run(path, args, null, workspace, Utilities.RunOptions.ThrowExceptionOnError, envVars); } } } diff --git a/Source/Tools/Flax.Build/Utilities/Utilities.cs b/Source/Tools/Flax.Build/Utilities/Utilities.cs index 72278c72e..a9a97bac0 100644 --- a/Source/Tools/Flax.Build/Utilities/Utilities.cs +++ b/Source/Tools/Flax.Build/Utilities/Utilities.cs @@ -244,6 +244,26 @@ namespace Flax.Build } } + /// + /// Deletes the directories inside a directory. + /// + /// The directory path. + /// The custom filter for the directories to delete. Can be used to select files to delete. Null if unused. + /// if set to true with sub-directories (recursive delete operation). + public static void DirectoriesDelete(string directoryPath, string searchPattern = null, bool withSubdirs = true) + { + if (!Directory.Exists(directoryPath)) + return; + if (searchPattern == null) + searchPattern = "*"; + + var directories = Directory.GetDirectories(directoryPath, searchPattern, withSubdirs ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); + for (int i = 0; i < directories.Length; i++) + { + DirectoryDelete(directories[i]); + } + } + /// /// The process run options. /// @@ -355,14 +375,14 @@ namespace Flax.Build Stopwatch stopwatch = Stopwatch.StartNew(); if (!options.HasFlag(RunOptions.NoLoggingOfRunCommand)) { - Log.Verbose("Running: " + app + " " + (string.IsNullOrEmpty(commandLine) ? "" : commandLine)); + Log.Verbose("Running: " + app + (string.IsNullOrEmpty(commandLine) ? "" : " " + commandLine)); } bool redirectStdOut = (options & RunOptions.NoStdOutRedirect) != RunOptions.NoStdOutRedirect; Process proc = new Process(); proc.StartInfo.FileName = app; - proc.StartInfo.Arguments = string.IsNullOrEmpty(commandLine) ? "" : commandLine; + proc.StartInfo.Arguments = commandLine != null ? commandLine : ""; proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardInput = input != null; proc.StartInfo.CreateNoWindow = true; @@ -386,7 +406,7 @@ namespace Flax.Build { if (env.Key == "PATH") { - proc.StartInfo.EnvironmentVariables[env.Key] = proc.StartInfo.EnvironmentVariables[env.Key] + ';' + env.Value; + proc.StartInfo.EnvironmentVariables[env.Key] = env.Value + ';' + proc.StartInfo.EnvironmentVariables[env.Key]; } else {