Merge remote-tracking branch 'origin/master' into gi

This commit is contained in:
Wojciech Figat
2022-04-11 10:37:23 +02:00
59 changed files with 471 additions and 314 deletions

View File

@@ -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:

View File

@@ -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;

View File

@@ -75,6 +75,7 @@ public:
{
struct
{
bool SupportDX12;
bool SupportDX11;
bool SupportDX10;
bool SupportVulkan;

View File

@@ -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;
}

View File

@@ -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);
}
}
/// <inheritdoc />
protected override void OnDurationFramesChanged()
{
@@ -137,6 +185,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
/// <inheritdoc />
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);
}
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}
},

View File

@@ -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))

View File

@@ -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))

View File

@@ -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.");
}
}
}

View File

@@ -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.");
}
}
}

View File

@@ -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.");
}
}
}

View File

@@ -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<Actor>(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<Actor>(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<Guid, Guid>(1024);

View File

@@ -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

View File

@@ -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();

View File

@@ -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

View File

@@ -319,10 +319,10 @@ namespace FlaxEditor.Viewport.Previews
// Create preview material (virtual)
var baseMaterial = FlaxEngine.Content.LoadAsyncInternal<Material>("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)

View File

@@ -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,7 +547,13 @@ namespace FlaxEditor.Windows
if (textBlock.Range.Length > 0)
{
// Parse compilation error/warning
var match = _compileRegex.Match(entryText, line.FirstCharIndex, textBlock.Range.Length);
var regexStart = line.FirstCharIndex;
if (j == 0)
regexStart += prefixLength;
var regexLength = line.LastCharIndex - regexStart;
if (regexLength > 0)
{
var match = _compileRegex.Match(entryText, regexStart, regexLength);
if (match.Success)
{
switch (match.Groups["level"].Value)
@@ -570,6 +575,7 @@ namespace FlaxEditor.Windows
// TODO: parsing hyperlinks with link
// TODO: parsing file paths with link
}
}
prevBlockBottom += line.Size.Y;
_textBlocks.Add(textBlock);

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,41 +0,0 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
using System;
namespace FlaxEngine
{
/// <summary>
/// Flax exception object.
/// </summary>
/// <seealso cref="System.SystemException" />
[Serializable]
public class FlaxException : SystemException
{
/// <summary>
/// Initializes a new instance of the <see cref="FlaxException"/> class.
/// </summary>
public FlaxException()
: base("A Flax runtime error occurred!")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FlaxException"/> class.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public FlaxException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="FlaxException"/> class.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception. If the <paramref name="innerException" /> parameter is not a null reference (Nothing in Visual Basic), the current exception is raised in a catch block that handles the inner exception.</param>
public FlaxException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

View File

@@ -154,7 +154,7 @@ namespace FlaxEngine
uv,
colors
))
throw new FlaxException("Failed to update mesh data.");
throw new Exception("Failed to update mesh data.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -247,7 +247,7 @@ namespace FlaxEngine
uv,
colors
))
throw new FlaxException("Failed to update mesh data.");
throw new Exception("Failed to update mesh data.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -341,7 +341,7 @@ namespace FlaxEngine
uv,
colors
))
throw new FlaxException("Failed to update mesh data.");
throw new Exception("Failed to update mesh data.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -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;
}
}

View File

@@ -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.");
}
/// <summary>
@@ -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.");
}
/// <summary>
@@ -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;
}
}

View File

@@ -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.");
}
}

View File

@@ -266,6 +266,20 @@ bool GPUDeviceDX11::Init()
}
UpdateOutputs(adapter);
ComPtr<IDXGIFactory5> 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<D3D_FEATURE_LEVEL>(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);

View File

@@ -50,6 +50,10 @@ public:
GPUDeviceDX11(IDXGIFactory* dxgiFactory, GPUAdapterDX* adapter);
~GPUDeviceDX11();
public:
bool AllowTearing = false;
public:
// Gets DX11 device

View File

@@ -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<IUnknown*>(_windowHandle), &swapChainDesc, nullptr, &_swapChain));

View File

@@ -23,6 +23,7 @@ private:
#if PLATFORM_WINDOWS
HWND _windowHandle;
IDXGISwapChain* _swapChain;
bool _allowTearing, _isFullscreen;
#else
IUnknown* _windowHandle;
IDXGISwapChain1* _swapChain;

View File

@@ -264,18 +264,20 @@ bool GPUDeviceDX12::Init()
return true;
}
UpdateOutputs(adapter);
{
ComPtr<IDXGIFactory5> 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 (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
VALIDATE_DIRECTX_RESULT(D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&_device)));

View File

@@ -51,6 +51,8 @@ GPUSwapChainDX12::GPUSwapChainDX12(GPUDeviceDX12* device, Window* window)
, _windowHandle(static_cast<HWND>(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
{

View File

@@ -39,6 +39,7 @@ typedef IGraphicsUnknown IDXGISwapChain3;
#include <D3D11.h>
#include <d3d11_1.h>
#include <dxgi1_3.h>
#include <dxgi1_5.h>
#endif
#if GRAPHICS_API_DIRECTX12
#include <dxgi1_5.h>

View File

@@ -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)

View File

@@ -76,7 +76,8 @@ void AnimatedModel::SetupSkinningData()
void AnimatedModel::PreInitSkinningData()
{
ASSERT(SkinnedModel && SkinnedModel->IsLoaded());
if (!SkinnedModel || !SkinnedModel->IsLoaded())
return;
ScopeLock lock(SkinnedModel->Locker);

View File

@@ -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);
}

View File

@@ -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"
/// <summary>
/// A base class for all physical actors.
/// </summary>
/// <seealso cref="Actor" />
API_CLASS(Abstract) class FLAXENGINE_API PhysicsActor : public Actor, public IPhysicsActor
{
DECLARE_SCENE_OBJECT_ABSTRACT(PhysicsActor);
protected:
Vector3 _cachedScale;
bool _isUpdatingTransform;
public:
/// <summary>
/// Updates the bounding box.
/// </summary>
void UpdateBounds();
public:
// [Actor]
bool IntersectsItself(const Ray& ray, float& distance, Vector3& normal) override;
// [IPhysicsActor]
void OnActiveTransformChanged() override;
protected:
// [Actor]
void OnTransformChanged() override;
};

View File

@@ -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,24 +512,19 @@ 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();
}
}
void RigidBody::OnPhysicsSceneChanged(PhysicsScene* previous)
{

View File

@@ -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;
/// <summary>
/// Physics simulation driven object.
/// </summary>
/// <seealso cref="PhysicsActor" />
API_CLASS() class FLAXENGINE_API RigidBody : public PhysicsActor
/// <seealso cref="Actor" />
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:
/// <summary>
/// Updates the bounding box.
/// </summary>
void UpdateBounds();
/// <summary>
/// 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;

View File

@@ -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();

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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());

View File

@@ -260,7 +260,7 @@ public:
private:
int32 _firstManagedTypeIndex;
int32 _firstManagedTypeIndex = 0;
Array<void*> _managedMemoryBlocks;
public:

View File

@@ -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")))

View File

@@ -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

View File

@@ -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());
}

View File

@@ -10,7 +10,7 @@
#include "ManagedCLR/MMethod.h"
#include <ThirdParty/mono-2.0/mono/metadata/mono-debug.h>
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();

View File

@@ -18,7 +18,7 @@ public:
/// </summary>
/// <param name="stream">The output stream.</param>
/// <param name="object">The object to serialize.</param>
static void Serialize(ISerializable::SerializeStream& stream, MonoObject* object);
static void Serialize(ISerializable::SerializeStream& stream, MObject* object);
/// <summary>
/// Serializes managed object difference to JSON.
@@ -26,20 +26,20 @@ public:
/// <param name="stream">The output stream.</param>
/// <param name="object">The object to serialize.</param>
/// <param name="other">The reference object to serialize diff compared to it.</param>
static void SerializeDiff(ISerializable::SerializeStream& stream, MonoObject* object, MonoObject* other);
static void SerializeDiff(ISerializable::SerializeStream& stream, MObject* object, MObject* other);
/// <summary>
/// Deserializes managed object from the JSON.
/// </summary>
/// <param name="stream">The input stream.</param>
/// <param name="object">The object to deserialize.</param>
static void Deserialize(ISerializable::DeserializeStream& stream, MonoObject* object);
static void Deserialize(ISerializable::DeserializeStream& stream, MObject* object);
/// <summary>
/// Deserializes managed object from the JSON.
/// </summary>
/// <param name="data">The input data.</param>
/// <param name="object">The object to deserialize.</param>
static void Deserialize(const StringAnsiView& data, MonoObject* object);
static void Deserialize(const StringAnsiView& data, MObject* object);
#endif
};

View File

@@ -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}).");
}
}

View File

@@ -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;
}
/// <summary>

View File

@@ -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.");
}
}

View File

@@ -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);
}
/// <summary>
/// Deserializes object from Json by reading it as a raw data (ver+length+bytes).
/// </summary>
@@ -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);
}
/// <summary>
/// Serializes object to Json and writes it as a raw data (ver+length+bytes).
/// </summary>

View File

@@ -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)
{

View File

@@ -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;
}

View File

@@ -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))
{

View File

@@ -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
/// <param name="solutionFile">Path to the solution file</param>
/// <param name="buildConfig">Configuration to build.</param>
/// <param name="buildPlatform">Platform to build.</param>
public static void BuildSolution(string solutionFile, string buildConfig, string buildPlatform)
/// <param name="props">Custom build properties mapping (property=value).</param>
public static void BuildSolution(string solutionFile, string buildConfig, string buildPlatform, Dictionary<string, string> 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)
{

View File

@@ -99,6 +99,18 @@ namespace Flax.Deps
}
}
/// <summary>
/// Clones the directory.
/// </summary>
/// <param name="src">The source folder path.</param>
/// <param name="dst">The destination folder path.</param>
public static void CloneDirectory(string src, string dst)
{
if (Directory.Exists(dst))
Utilities.DirectoryDelete(dst);
Utilities.DirectoryCopy(src, dst);
}
/// <summary>
/// Clones the git repository from the remote url (full repository).
/// </summary>
@@ -275,30 +287,76 @@ namespace Flax.Deps
/// </summary>
/// <param name="path">The path.</param>
/// <param name="workspace">The workspace folder.</param>
/// <param name="envVars">Custom environment variables to pass to the child process.</param>
public static void RunCygwin(string path, string workspace = null, Dictionary<string, string> envVars = null)
public static void RunCygwin(string path, string workspace = null)
{
RunBash(path, string.Empty, workspace);
}
/// <summary>
/// Runs the bash script (executes natively on Unix platforms, uses Cygwin on Windows).
/// </summary>
/// <param name="path">The script or command path.</param>
/// <param name="args">The arguments.</param>
/// <param name="workspace">The workspace folder.</param>
/// <param name="envVars">Custom environment variables to pass to the child process.</param>
public static void RunBash(string path, string args = null, string workspace = null, Dictionary<string, string> 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))
{
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.");
}
app = Path.Combine(cygwinFolder, "bin\\bash.exe");
}
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<string, string>();
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);
}
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);
}
}
}

View File

@@ -244,6 +244,26 @@ namespace Flax.Build
}
}
/// <summary>
/// Deletes the directories inside a directory.
/// </summary>
/// <param name="directoryPath">The directory path.</param>
/// <param name="searchPattern">The custom filter for the directories to delete. Can be used to select files to delete. Null if unused.</param>
/// <param name="withSubdirs">if set to <c>true</c> with sub-directories (recursive delete operation).</param>
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]);
}
}
/// <summary>
/// The process run options.
/// </summary>
@@ -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
{