Merge remote-tracking branch 'origin/master' into visject_grid_snap
This commit is contained in:
@@ -36,7 +36,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
return;
|
||||
var gizmos = gizmoOwner.Gizmos;
|
||||
_gizmoMode = new ClothPaintingGizmoMode();
|
||||
|
||||
|
||||
var projectCache = Editor.Instance.ProjectCache;
|
||||
if (projectCache.TryGetCustomData("ClothGizmoPaintValue", out var cachedPaintValue))
|
||||
_gizmoMode.PaintValue = JsonSerializer.Deserialize<float>(cachedPaintValue);
|
||||
@@ -48,7 +48,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_gizmoMode.BrushSize = JsonSerializer.Deserialize<float>(cachedBrushSize);
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushStrength", out var cachedBrushStrength))
|
||||
_gizmoMode.BrushStrength = JsonSerializer.Deserialize<float>(cachedBrushStrength);
|
||||
|
||||
|
||||
gizmos.AddMode(_gizmoMode);
|
||||
_prevMode = gizmos.ActiveMode;
|
||||
gizmos.ActiveMode = _gizmoMode;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// <summary>
|
||||
/// [Deprecated on 26.05.2022, expires on 26.05.2024]
|
||||
/// </summary>
|
||||
[System.Obsolete("Deprecated in 1.4")]
|
||||
[System.Obsolete("Deprecated in 1.4, use ValueBox instead")]
|
||||
public DoubleValueBox DoubleValue => ValueBox;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace FlaxEditor.CustomEditors.Elements
|
||||
/// <summary>
|
||||
/// [Deprecated on 26.05.2022, expires on 26.05.2024]
|
||||
/// </summary>
|
||||
[System.Obsolete("Deprecated in 1.4, ValueBox instead")]
|
||||
[System.Obsolete("Deprecated in 1.4, use ValueBox instead")]
|
||||
public FloatValueBox FloatValue => ValueBox;
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace FlaxEditor
|
||||
{
|
||||
foreach (var preview in activePreviews)
|
||||
{
|
||||
if (preview == loadingPreview ||
|
||||
if (preview == loadingPreview ||
|
||||
(preview.Instance != null && (preview.Instance == control || preview.Instance.HasActorInHierarchy(control))))
|
||||
{
|
||||
// Link it to the prefab preview to see it in the editor
|
||||
|
||||
@@ -482,8 +482,8 @@ namespace FlaxEditor.GUI
|
||||
Focus();
|
||||
});
|
||||
if (_selected != null)
|
||||
{
|
||||
var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path);
|
||||
{
|
||||
var selectedAssetName = Path.GetFileNameWithoutExtension(_selected.Path);
|
||||
popup.ScrollToAndHighlightItemByName(selectedAssetName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Hide parent CM popups and set itself as child
|
||||
parentContextMenu.ShowChild(ContextMenu, PointToParent(ParentContextMenu, new Float2(Width, 0)));
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
|
||||
@@ -293,7 +293,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
if (Root != null)
|
||||
{
|
||||
bool shiftDown = Root.GetKey(KeyboardKeys.Shift);
|
||||
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||
Root.Navigate(shiftDown ? NavDirection.Previous : NavDirection.Next);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace FlaxEditor.GUI.Input
|
||||
: this(false, 0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Init search box
|
||||
/// </summary>
|
||||
@@ -28,7 +28,7 @@ namespace FlaxEditor.GUI.Input
|
||||
: base(isMultiline, x, y, width)
|
||||
{
|
||||
WatermarkText = "Search...";
|
||||
|
||||
|
||||
ClearSearchButton = new Button
|
||||
{
|
||||
Parent = this,
|
||||
|
||||
@@ -182,6 +182,7 @@ namespace FlaxEditor.GUI.Input
|
||||
}
|
||||
SlidingEnd?.Invoke();
|
||||
Defocus();
|
||||
Parent?.Focus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -241,7 +241,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
DoubleClick?.Invoke();
|
||||
RowDoubleClick?.Invoke(this);
|
||||
|
||||
|
||||
return base.OnMouseDoubleClick(location, button);
|
||||
}
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ namespace FlaxEditor.Modules
|
||||
hint = "Too long name.";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (item.IsFolder && shortName.EndsWith("."))
|
||||
{
|
||||
hint = "Name cannot end with '.'";
|
||||
|
||||
@@ -133,7 +133,7 @@ namespace FlaxEditor.Modules
|
||||
return;
|
||||
var actorsList = new List<Actor>();
|
||||
Utilities.Utils.GetActorsTree(actorsList, actor);
|
||||
|
||||
|
||||
var actions = new IUndoAction[actorsList.Count];
|
||||
for (int i = 0; i < actorsList.Count; i++)
|
||||
actions[i] = BreakPrefabLinkAction.Linked(actorsList[i]);
|
||||
|
||||
@@ -453,7 +453,7 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
Editor.Windows.SceneWin.Focus();
|
||||
}
|
||||
|
||||
|
||||
// fix scene window layout
|
||||
Editor.Windows.SceneWin.PerformLayout();
|
||||
Editor.Windows.SceneWin.PerformLayout();
|
||||
@@ -520,7 +520,7 @@ namespace FlaxEditor.Modules
|
||||
Undo.AddAction(new MultiUndoAction(pasteAction, selectAction));
|
||||
OnSelectionChanged();
|
||||
}
|
||||
|
||||
|
||||
// Scroll to new selected node while pasting
|
||||
Editor.Windows.SceneWin.ScrollToSelectedNode();
|
||||
}
|
||||
@@ -620,7 +620,7 @@ namespace FlaxEditor.Modules
|
||||
Undo.AddAction(new MultiUndoAction(undoActions));
|
||||
OnSelectionChanged();
|
||||
}
|
||||
|
||||
|
||||
// Scroll to new selected node while duplicating
|
||||
Editor.Windows.SceneWin.ScrollToSelectedNode();
|
||||
}
|
||||
|
||||
@@ -332,7 +332,7 @@ namespace FlaxEditor.Modules
|
||||
continue;
|
||||
scenes.Add(s);
|
||||
}
|
||||
|
||||
|
||||
// In play-mode Editor mocks the level streaming script
|
||||
if (Editor.IsPlayMode)
|
||||
{
|
||||
|
||||
@@ -29,10 +29,10 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
|
||||
private static bool CheckFunc(ScriptType scriptType)
|
||||
{
|
||||
if (scriptType.IsStatic ||
|
||||
scriptType.IsGenericType ||
|
||||
!scriptType.IsPublic ||
|
||||
scriptType.HasAttribute(typeof(HideInEditorAttribute), true) ||
|
||||
if (scriptType.IsStatic ||
|
||||
scriptType.IsGenericType ||
|
||||
!scriptType.IsPublic ||
|
||||
scriptType.HasAttribute(typeof(HideInEditorAttribute), true) ||
|
||||
scriptType.HasAttribute(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute), false))
|
||||
return false;
|
||||
var managedType = TypeUtils.GetType(scriptType);
|
||||
|
||||
@@ -299,7 +299,7 @@ namespace FlaxEditor.Modules
|
||||
else
|
||||
text = "Ready";
|
||||
|
||||
if(ProgressVisible)
|
||||
if (ProgressVisible)
|
||||
{
|
||||
color = Style.Current.Statusbar.Loading;
|
||||
}
|
||||
@@ -402,7 +402,7 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
UpdateStatusBar();
|
||||
}
|
||||
else if(ProgressVisible)
|
||||
else if (ProgressVisible)
|
||||
{
|
||||
UpdateStatusBar();
|
||||
}
|
||||
@@ -557,7 +557,7 @@ namespace FlaxEditor.Modules
|
||||
cm.AddButton("Game Settings", () =>
|
||||
{
|
||||
var item = Editor.ContentDatabase.Find(GameSettings.GameSettingsAssetPath);
|
||||
if(item != null)
|
||||
if (item != null)
|
||||
Editor.ContentEditing.Open(item);
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace FlaxEditor.Progress
|
||||
/// </summary>
|
||||
/// <param name="handler">The calling handler.</param>
|
||||
public delegate void ProgressDelegate(ProgressHandler handler);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Progress failed handler event delegate
|
||||
/// </summary>
|
||||
@@ -127,7 +127,7 @@ namespace FlaxEditor.Progress
|
||||
{
|
||||
if (!_isActive)
|
||||
throw new InvalidOperationException("Already ended.");
|
||||
|
||||
|
||||
_isActive = false;
|
||||
_progress = 0;
|
||||
_infoText = string.Empty;
|
||||
|
||||
@@ -34,6 +34,9 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <seealso cref="FlaxEditor.Surface.SurfaceNode" />
|
||||
public class Sample : SurfaceNode
|
||||
{
|
||||
private AssetSelect _assetSelect;
|
||||
private Box _assetBox;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Sample(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
@@ -54,16 +57,42 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
base.OnSurfaceLoaded(action);
|
||||
|
||||
if (Surface != null)
|
||||
{
|
||||
_assetSelect = GetChild<AssetSelect>();
|
||||
if (TryGetBox(8, out var box))
|
||||
{
|
||||
_assetBox = box;
|
||||
_assetSelect.Visible = !_assetBox.HasAnyConnection;
|
||||
}
|
||||
UpdateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateTitle()
|
||||
{
|
||||
var asset = Editor.Instance.ContentDatabase.Find((Guid)Values[0]);
|
||||
Title = asset?.ShortName ?? "Animation";
|
||||
if (_assetBox != null)
|
||||
Title = _assetBox.HasAnyConnection || asset == null ? "Animation" : asset.ShortName;
|
||||
else
|
||||
Title = asset?.ShortName ?? "Animation";
|
||||
|
||||
var style = Style.Current;
|
||||
Resize(Mathf.Max(230, style.FontLarge.MeasureText(Title).X + 30), 160);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void ConnectionTick(Box box)
|
||||
{
|
||||
base.ConnectionTick(box);
|
||||
|
||||
if (_assetBox == null)
|
||||
return;
|
||||
if (box.ID != _assetBox.ID)
|
||||
return;
|
||||
|
||||
_assetSelect.Visible = !box.HasAnyConnection;
|
||||
UpdateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -305,7 +334,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Input(0, "Speed", true, typeof(float), 5, 1),
|
||||
NodeElementArchetype.Factory.Input(1, "Loop", true, typeof(bool), 6, 2),
|
||||
NodeElementArchetype.Factory.Input(2, "Start Position", true, typeof(float), 7, 3),
|
||||
NodeElementArchetype.Factory.Asset(0, Surface.Constants.LayoutOffsetY * 3, 0, typeof(FlaxEngine.Animation)),
|
||||
NodeElementArchetype.Factory.Input(3, "Animation Asset", true, typeof(FlaxEngine.Animation), 8),
|
||||
NodeElementArchetype.Factory.Asset(0, Surface.Constants.LayoutOffsetY * 4, 0, typeof(FlaxEngine.Animation)),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
|
||||
@@ -510,7 +510,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
for (var i = 0; i < elements.Length; i++)
|
||||
{
|
||||
if(elements[i].Type != NodeElementType.Output)
|
||||
if (elements[i].Type != NodeElementType.Output)
|
||||
continue;
|
||||
|
||||
if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, inputType, hint))
|
||||
@@ -533,7 +533,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
for (var i = 0; i < elements.Length; i++)
|
||||
{
|
||||
if(elements[i].Type != NodeElementType.Input)
|
||||
if (elements[i].Type != NodeElementType.Input)
|
||||
continue;
|
||||
if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, outputType, hint))
|
||||
return true;
|
||||
@@ -725,7 +725,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool UseNormalMaps => false;
|
||||
|
||||
|
||||
internal new static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context)
|
||||
{
|
||||
if (inputType == ScriptType.Object)
|
||||
@@ -743,7 +743,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
for (var i = 0; i < elements.Length; i++)
|
||||
{
|
||||
if(elements[i].Type != NodeElementType.Output)
|
||||
if (elements[i].Type != NodeElementType.Output)
|
||||
continue;
|
||||
if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, inputType, hint))
|
||||
return true;
|
||||
@@ -765,7 +765,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
for (var i = 0; i < elements.Length; i++)
|
||||
{
|
||||
if(elements[i].Type != NodeElementType.Input)
|
||||
if (elements[i].Type != NodeElementType.Input)
|
||||
continue;
|
||||
if (VisjectSurface.FullCastCheck(elements[i].ConnectionsType, outputType, hint))
|
||||
return true;
|
||||
@@ -789,7 +789,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool UseNormalMaps => false;
|
||||
|
||||
|
||||
internal new static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context)
|
||||
{
|
||||
if (inputType == ScriptType.Object)
|
||||
@@ -987,7 +987,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_combobox.Width = Width - 50;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
internal static bool IsOutputCompatible(NodeArchetype nodeArch, ScriptType inputType, ConnectionsHint hint, VisjectSurfaceContext context)
|
||||
{
|
||||
return inputType == ScriptType.Void;
|
||||
@@ -997,7 +997,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
if (outputType == ScriptType.Void)
|
||||
return true;
|
||||
|
||||
|
||||
SurfaceParameter parameter = context.GetParameter((Guid)nodeArch.DefaultValues[0]);
|
||||
ScriptType type = parameter?.Type ?? ScriptType.Null;
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
if (_connectionInstigator is Archetypes.Tools.RerouteNode)
|
||||
{
|
||||
if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true})
|
||||
if (endPos.X < startPos.X && _lastInstigatorUnderMouse is null or Box { IsOutput: true })
|
||||
{
|
||||
actualStartPos = endPos;
|
||||
actualEndPos = startPos;
|
||||
|
||||
@@ -150,6 +150,12 @@ namespace FlaxEditor.Tools.Terrain
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase or decrease brush size with scroll
|
||||
if (Input.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f;
|
||||
}
|
||||
|
||||
// Check if no terrain is selected
|
||||
var terrain = SelectedTerrain;
|
||||
if (!terrain)
|
||||
|
||||
@@ -158,6 +158,12 @@ namespace FlaxEditor.Tools.Terrain
|
||||
return;
|
||||
}
|
||||
|
||||
// Increase or decrease brush size with scroll
|
||||
if (Input.GetKey(KeyboardKeys.Shift))
|
||||
{
|
||||
Mode.CurrentBrush.Size += dt * Mode.CurrentBrush.Size * Input.Mouse.ScrollDelta * 5f;
|
||||
}
|
||||
|
||||
// Check if selected terrain was changed during painting
|
||||
if (terrain != _paintTerrain && IsPainting)
|
||||
{
|
||||
|
||||
@@ -49,7 +49,16 @@ namespace FlaxEditor.Actions
|
||||
_scriptTypeName = script.TypeName;
|
||||
_prefabId = script.PrefabID;
|
||||
_prefabObjectId = script.PrefabObjectID;
|
||||
_scriptData = FlaxEngine.Json.JsonSerializer.Serialize(script);
|
||||
try
|
||||
{
|
||||
_scriptData = FlaxEngine.Json.JsonSerializer.Serialize(script);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_scriptData = null;
|
||||
Debug.LogError("Failed to serialize script data for Undo due to exception");
|
||||
Debug.LogException(ex);
|
||||
}
|
||||
_parentId = script.Actor.ID;
|
||||
_orderInParent = script.OrderInParent;
|
||||
_enabled = script.Enabled;
|
||||
|
||||
@@ -1119,7 +1119,12 @@ namespace FlaxEditor.Viewport
|
||||
var win = (WindowRootControl)Root;
|
||||
|
||||
// Get current mouse position in the view
|
||||
_viewMousePos = PointFromWindow(win.MousePosition);
|
||||
{
|
||||
// When the window is not focused, the position in window does not return sane values
|
||||
Float2 pos = PointFromWindow(win.MousePosition);
|
||||
if (!float.IsInfinity(pos.LengthSquared))
|
||||
_viewMousePos = pos;
|
||||
}
|
||||
|
||||
// Update input
|
||||
var window = win.Window;
|
||||
|
||||
@@ -171,7 +171,7 @@ namespace FlaxEditor.Viewport.Previews
|
||||
case DrawModes.Fill:
|
||||
clipsInView = 1.0f;
|
||||
clipWidth = width;
|
||||
samplesPerIndex = (uint)(samplesPerChannel / width);
|
||||
samplesPerIndex = (uint)(samplesPerChannel / width) * info.NumChannels;
|
||||
break;
|
||||
case DrawModes.Single:
|
||||
clipsInView = Mathf.Min(clipsInView, 1.0f);
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace FlaxEditor
|
||||
if (_highlightMaterial == null
|
||||
|| (_highlights.Count == 0 && _highlightTriangles.Count == 0)
|
||||
|| renderContext.View.Pass == DrawPass.Depth
|
||||
)
|
||||
)
|
||||
return;
|
||||
Profiler.BeginEvent("ViewportDebugDrawData.OnDraw");
|
||||
|
||||
|
||||
@@ -335,6 +335,22 @@ namespace FlaxEditor.Windows.Assets
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
if (base.OnKeyDown(key))
|
||||
return true;
|
||||
|
||||
if (key == KeyboardKeys.Spacebar)
|
||||
{
|
||||
if (_previewSource?.State == AudioSource.States.Playing)
|
||||
OnPause();
|
||||
else
|
||||
OnPlay();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool UseLayoutData => true;
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
OnPasteAction(pasteAction);
|
||||
}
|
||||
|
||||
|
||||
// Scroll to new selected node
|
||||
ScrollToSelectedNode();
|
||||
}
|
||||
@@ -183,7 +183,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
OnPasteAction(pasteAction);
|
||||
}
|
||||
|
||||
|
||||
// Scroll to new selected node
|
||||
ScrollToSelectedNode();
|
||||
}
|
||||
@@ -334,7 +334,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
}, action2.ActionString);
|
||||
action.Do();
|
||||
Undo.AddAction(action);
|
||||
|
||||
|
||||
_treePanel.PerformLayout();
|
||||
_treePanel.PerformLayout();
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
InputActions.Add(options => options.Rename, Rename);
|
||||
InputActions.Add(options => options.FocusSelection, _viewport.FocusSelection);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables vertical and horizontal scrolling on the tree panel.
|
||||
/// </summary>
|
||||
@@ -257,7 +257,7 @@ namespace FlaxEditor.Windows.Assets
|
||||
{
|
||||
if (base.OnMouseUp(location, button))
|
||||
return true;
|
||||
|
||||
|
||||
if (button == MouseButton.Right && _treePanel.ContainsPoint(ref location))
|
||||
{
|
||||
_tree.Deselect();
|
||||
|
||||
@@ -128,7 +128,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
_tableRep.IsLayoutLocked = true;
|
||||
RecycleTableRows(_tableRpc, _tableRowsCache);
|
||||
RecycleTableRows(_tableRep, _tableRowsCache);
|
||||
|
||||
|
||||
var events = _events.Get(selectedFrame);
|
||||
var rowCount = Int2.Zero;
|
||||
if (events != null && events.Length != 0)
|
||||
@@ -186,7 +186,7 @@ namespace FlaxEditor.Windows.Profiler
|
||||
_tableRep.Visible = rowCount.Y != 0;
|
||||
_tableRpc.Children.Sort(SortRows);
|
||||
_tableRep.Children.Sort(SortRows);
|
||||
|
||||
|
||||
_tableRpc.UnlockChildrenRecursive();
|
||||
_tableRpc.PerformLayout();
|
||||
_tableRep.UnlockChildrenRecursive();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "AnimGraph.h"
|
||||
#include "Engine/Core/Types/VariantValueCast.h"
|
||||
#include "Engine/Content/Assets/Animation.h"
|
||||
#include "Engine/Content/Assets/SkeletonMask.h"
|
||||
#include "Engine/Content/Assets/AnimationGraphFunction.h"
|
||||
@@ -530,7 +531,7 @@ void AnimGraphExecutor::UpdateStateTransitions(AnimGraphContext& context, const
|
||||
transitionData.Position = 0;
|
||||
transitionData.Length = ZeroTolerance;
|
||||
}
|
||||
|
||||
|
||||
const bool useDefaultRule = EnumHasAnyFlags(transition.Flags, AnimGraphStateTransition::FlagTypes::UseDefaultRule);
|
||||
if (transition.RuleGraph && !useDefaultRule)
|
||||
{
|
||||
@@ -750,9 +751,16 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
||||
// Animation
|
||||
case 2:
|
||||
{
|
||||
const auto anim = node->Assets[0].As<Animation>();
|
||||
auto anim = node->Assets[0].As<Animation>();
|
||||
auto& bucket = context.Data->State[node->BucketIndex].Animation;
|
||||
|
||||
// Override animation when animation reference box is connected
|
||||
auto animationAssetBox = node->TryGetBox(8);
|
||||
if (animationAssetBox && animationAssetBox->HasConnection())
|
||||
{
|
||||
anim = TVariantValueCast<Animation*>::Cast(tryGetValue(animationAssetBox, Value::Null));
|
||||
}
|
||||
|
||||
switch (box->ID)
|
||||
{
|
||||
// Animation
|
||||
|
||||
@@ -187,7 +187,6 @@ float AudioSource::GetTime() const
|
||||
return 0.0f;
|
||||
|
||||
float time = AudioBackend::Source::GetCurrentBufferTime(this);
|
||||
ASSERT(time >= 0.0f && time <= Clip->GetLength());
|
||||
|
||||
if (UseStreaming())
|
||||
{
|
||||
|
||||
@@ -27,7 +27,15 @@
|
||||
#define MAX_INPUT_CHANNELS 2
|
||||
#define MAX_OUTPUT_CHANNELS 8
|
||||
#define MAX_CHANNELS_MATRIX_SIZE (MAX_INPUT_CHANNELS*MAX_OUTPUT_CHANNELS)
|
||||
|
||||
#if ENABLE_ASSERTION
|
||||
#define XAUDIO2_CHECK_ERROR(method) \
|
||||
if (hr != 0) \
|
||||
{ \
|
||||
LOG(Error, "XAudio2 method {0} failed with error 0x{1:X} (at line {2})", TEXT(#method), (uint32)hr, __LINE__ - 1); \
|
||||
}
|
||||
#else
|
||||
#define XAUDIO2_CHECK_ERROR(method)
|
||||
#endif
|
||||
#define FLAX_COORD_SCALE 0.01f // units are meters
|
||||
#define FLAX_DST_TO_XAUDIO(x) x * FLAX_COORD_SCALE
|
||||
#define FLAX_POS_TO_XAUDIO(vec) X3DAUDIO_VECTOR(vec.X * FLAX_COORD_SCALE, vec.Y * FLAX_COORD_SCALE, vec.Z * FLAX_COORD_SCALE)
|
||||
@@ -104,7 +112,9 @@ namespace XAudio2
|
||||
|
||||
COM_DECLSPEC_NOTHROW void STDMETHODCALLTYPE OnVoiceError(THIS_ void* pBufferContext, HRESULT Error) override
|
||||
{
|
||||
#if ENABLE_ASSERTION
|
||||
LOG(Warning, "IXAudio2VoiceCallback::OnVoiceError! Error: 0x{0:x}", Error);
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -121,7 +131,8 @@ namespace XAudio2
|
||||
XAUDIO2_SEND_DESCRIPTOR Destination;
|
||||
float Pitch;
|
||||
float Pan;
|
||||
float StartTime;
|
||||
float StartTimeForQueueBuffer;
|
||||
float LastBufferStartTime;
|
||||
float DopplerFactor;
|
||||
uint64 LastBufferStartSamplesPlayed;
|
||||
int32 BuffersProcessed;
|
||||
@@ -145,7 +156,8 @@ namespace XAudio2
|
||||
Destination.pOutputVoice = nullptr;
|
||||
Pitch = 1.0f;
|
||||
Pan = 0.0f;
|
||||
StartTime = 0.0f;
|
||||
StartTimeForQueueBuffer = 0.0f;
|
||||
LastBufferStartTime = 0.0f;
|
||||
IsDirty = false;
|
||||
Is3D = false;
|
||||
IsPlaying = false;
|
||||
@@ -255,18 +267,18 @@ namespace XAudio2
|
||||
buffer.pAudioData = aBuffer->Data.Get();
|
||||
buffer.AudioBytes = aBuffer->Data.Count();
|
||||
|
||||
if (aSource->StartTime > ZeroTolerance)
|
||||
if (aSource->StartTimeForQueueBuffer > ZeroTolerance)
|
||||
{
|
||||
buffer.PlayBegin = (UINT32)(aSource->StartTime * (aBuffer->Info.SampleRate * aBuffer->Info.NumChannels));
|
||||
buffer.PlayLength = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels - buffer.PlayBegin;
|
||||
aSource->StartTime = 0;
|
||||
// Offset start position when playing buffer with a custom time offset
|
||||
const uint32 bytesPerSample = aBuffer->Info.BitDepth / 8 * aBuffer->Info.NumChannels;
|
||||
buffer.PlayBegin = (UINT32)(aSource->StartTimeForQueueBuffer * aBuffer->Info.SampleRate);
|
||||
buffer.PlayLength = (buffer.AudioBytes / bytesPerSample) - buffer.PlayBegin;
|
||||
aSource->LastBufferStartTime = aSource->StartTimeForQueueBuffer;
|
||||
aSource->StartTimeForQueueBuffer = 0;
|
||||
}
|
||||
|
||||
const HRESULT hr = aSource->Voice->SubmitSourceBuffer(&buffer);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG(Warning, "XAudio2: Failed to submit source buffer (error: 0x{0:x})", hr);
|
||||
}
|
||||
XAUDIO2_CHECK_ERROR(SubmitSourceBuffer);
|
||||
}
|
||||
|
||||
void VoiceCallback::OnBufferEnd(void* pBufferContext)
|
||||
@@ -375,7 +387,7 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
const auto& header = clip->AudioHeader;
|
||||
auto& format = aSource->Format;
|
||||
format.wFormatTag = WAVE_FORMAT_PCM;
|
||||
format.nChannels = source->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write)
|
||||
format.nChannels = clip->Is3D() ? 1 : header.Info.NumChannels; // 3d audio is always mono (AudioClip auto-converts before buffer write)
|
||||
format.nSamplesPerSec = header.Info.SampleRate;
|
||||
format.wBitsPerSample = header.Info.BitDepth;
|
||||
format.nBlockAlign = (WORD)(format.nChannels * (format.wBitsPerSample / 8));
|
||||
@@ -391,12 +403,10 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
1,
|
||||
&aSource->Destination
|
||||
};
|
||||
const HRESULT hr = XAudio2::Instance->CreateSourceVoice(&aSource->Voice, &aSource->Format, 0, 2.0f, &aSource->Callback, &sendList);
|
||||
HRESULT hr = XAudio2::Instance->CreateSourceVoice(&aSource->Voice, &aSource->Format, 0, 2.0f, &aSource->Callback, &sendList);
|
||||
XAUDIO2_CHECK_ERROR(CreateSourceVoice);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG(Error, "Failed to create XAudio2 voice. Error: 0x{0:x}", hr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare source state
|
||||
aSource->Callback.Source = source;
|
||||
@@ -410,7 +420,8 @@ void AudioBackendXAudio2::Source_OnAdd(AudioSource* source)
|
||||
aSource->DopplerFactor = source->GetDopplerFactor();
|
||||
aSource->UpdateTransform(source);
|
||||
aSource->UpdateVelocity(source);
|
||||
aSource->Voice->SetVolume(source->GetVolume());
|
||||
hr = aSource->Voice->SetVolume(source->GetVolume());
|
||||
XAUDIO2_CHECK_ERROR(SetVolume);
|
||||
|
||||
// 0 is invalid ID so shift them
|
||||
sourceID++;
|
||||
@@ -451,7 +462,8 @@ void AudioBackendXAudio2::Source_VolumeChanged(AudioSource* source)
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
aSource->Voice->SetVolume(source->GetVolume());
|
||||
const HRESULT hr = aSource->Voice->SetVolume(source->GetVolume());
|
||||
XAUDIO2_CHECK_ERROR(SetVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,12 +506,18 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Locker.Unlock();
|
||||
|
||||
HRESULT hr;
|
||||
const bool isPlaying = source->IsActuallyPlayingSth();
|
||||
if (isPlaying)
|
||||
aSource->Voice->Stop();
|
||||
{
|
||||
hr = aSource->Voice->Stop();
|
||||
XAUDIO2_CHECK_ERROR(Stop);
|
||||
}
|
||||
|
||||
aSource->Voice->FlushSourceBuffers();
|
||||
hr = aSource->Voice->FlushSourceBuffers();
|
||||
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
||||
aSource->LastBufferStartSamplesPlayed = 0;
|
||||
aSource->LastBufferStartTime = 0;
|
||||
aSource->BuffersProcessed = 0;
|
||||
|
||||
XAUDIO2_BUFFER buffer = { 0 };
|
||||
@@ -512,12 +530,15 @@ void AudioBackendXAudio2::Source_IsLoopingChanged(AudioSource* source)
|
||||
const UINT32 totalSamples = aBuffer->Info.NumSamples / aBuffer->Info.NumChannels;
|
||||
buffer.PlayBegin = state.SamplesPlayed % totalSamples;
|
||||
buffer.PlayLength = totalSamples - buffer.PlayBegin;
|
||||
aSource->StartTime = 0;
|
||||
aSource->StartTimeForQueueBuffer = 0;
|
||||
|
||||
XAudio2::QueueBuffer(aSource, source, bufferId, buffer);
|
||||
|
||||
if (isPlaying)
|
||||
aSource->Voice->Start();
|
||||
{
|
||||
hr = aSource->Voice->Start();
|
||||
XAUDIO2_CHECK_ERROR(Start);
|
||||
}
|
||||
}
|
||||
|
||||
void AudioBackendXAudio2::Source_SpatialSetupChanged(AudioSource* source)
|
||||
@@ -572,7 +593,8 @@ void AudioBackendXAudio2::Source_Play(AudioSource* source)
|
||||
if (aSource && aSource->Voice && !aSource->IsPlaying)
|
||||
{
|
||||
// Play
|
||||
aSource->Voice->Start();
|
||||
const HRESULT hr = aSource->Voice->Start();
|
||||
XAUDIO2_CHECK_ERROR(Start);
|
||||
aSource->IsPlaying = true;
|
||||
}
|
||||
}
|
||||
@@ -583,7 +605,8 @@ void AudioBackendXAudio2::Source_Pause(AudioSource* source)
|
||||
if (aSource && aSource->Voice && aSource->IsPlaying)
|
||||
{
|
||||
// Pause
|
||||
aSource->Voice->Stop();
|
||||
const HRESULT hr = aSource->Voice->Stop();
|
||||
XAUDIO2_CHECK_ERROR(Stop);
|
||||
aSource->IsPlaying = false;
|
||||
}
|
||||
}
|
||||
@@ -593,14 +616,18 @@ void AudioBackendXAudio2::Source_Stop(AudioSource* source)
|
||||
auto aSource = XAudio2::GetSource(source);
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
aSource->StartTime = 0.0f;
|
||||
aSource->StartTimeForQueueBuffer = 0.0f;
|
||||
aSource->LastBufferStartTime = 0.0f;
|
||||
|
||||
// Pause
|
||||
aSource->Voice->Stop();
|
||||
HRESULT hr = aSource->Voice->Stop();
|
||||
XAUDIO2_CHECK_ERROR(Stop);
|
||||
aSource->IsPlaying = false;
|
||||
|
||||
// Unset streaming buffers to rewind
|
||||
aSource->Voice->FlushSourceBuffers();
|
||||
hr = aSource->Voice->FlushSourceBuffers();
|
||||
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
||||
Platform::Sleep(10); // TODO: find a better way to handle case when VoiceCallback::OnBufferEnd is called after source was stopped thus BuffersProcessed != 0, probably via buffers contexts ptrs
|
||||
aSource->BuffersProcessed = 0;
|
||||
aSource->Callback.PeekSamples();
|
||||
}
|
||||
@@ -612,7 +639,7 @@ void AudioBackendXAudio2::Source_SetCurrentBufferTime(AudioSource* source, float
|
||||
if (aSource)
|
||||
{
|
||||
// Store start time so next buffer submitted will start from here (assumes audio is stopped)
|
||||
aSource->StartTime = value;
|
||||
aSource->StartTimeForQueueBuffer = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -628,8 +655,9 @@ float AudioBackendXAudio2::Source_GetCurrentBufferTime(const AudioSource* source
|
||||
aSource->Voice->GetState(&state);
|
||||
const uint32 numChannels = clipInfo.NumChannels;
|
||||
const uint32 totalSamples = clipInfo.NumSamples / numChannels;
|
||||
const uint32 sampleRate = clipInfo.SampleRate;// / clipInfo.NumChannels;
|
||||
state.SamplesPlayed -= aSource->LastBufferStartSamplesPlayed % totalSamples; // Offset by the last buffer start to get time relative to its begin
|
||||
time = aSource->StartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, clipInfo.SampleRate));
|
||||
time = aSource->LastBufferStartTime + (state.SamplesPlayed % totalSamples) / static_cast<float>(Math::Max(1U, sampleRate));
|
||||
}
|
||||
return time;
|
||||
}
|
||||
@@ -697,10 +725,7 @@ void AudioBackendXAudio2::Source_DequeueProcessedBuffers(AudioSource* source)
|
||||
if (aSource && aSource->Voice)
|
||||
{
|
||||
const HRESULT hr = aSource->Voice->FlushSourceBuffers();
|
||||
if (FAILED(hr))
|
||||
{
|
||||
LOG(Warning, "XAudio2: FlushSourceBuffers failed. Error: 0x{0:x}", hr);
|
||||
}
|
||||
XAUDIO2_CHECK_ERROR(FlushSourceBuffers);
|
||||
aSource->BuffersProcessed = 0;
|
||||
}
|
||||
}
|
||||
@@ -749,8 +774,7 @@ void AudioBackendXAudio2::Buffer_Write(uint32 bufferId, byte* samples, const Aud
|
||||
XAudio2::Buffer* aBuffer = XAudio2::Buffers[bufferId - 1];
|
||||
XAudio2::Locker.Unlock();
|
||||
|
||||
const uint32 bytesPerSample = info.BitDepth / 8;
|
||||
const int32 samplesLength = info.NumSamples * bytesPerSample;
|
||||
const uint32 samplesLength = info.NumSamples * info.BitDepth / 8;
|
||||
|
||||
aBuffer->Info = info;
|
||||
aBuffer->Data.Set(samples, samplesLength);
|
||||
@@ -779,7 +803,8 @@ void AudioBackendXAudio2::Base_SetVolume(float value)
|
||||
{
|
||||
if (XAudio2::MasteringVoice)
|
||||
{
|
||||
XAudio2::MasteringVoice->SetVolume(value);
|
||||
const HRESULT hr = XAudio2::MasteringVoice->SetVolume(value);
|
||||
XAUDIO2_CHECK_ERROR(SetVolume);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ public:
|
||||
/// <param name="g">The green channel value.</param>
|
||||
/// <param name="b">The blue channel value.</param>
|
||||
/// <param name="a">The alpha channel value.</param>
|
||||
Color(float r, float g, float b, float a = 1)
|
||||
FORCE_INLINE Color(float r, float g, float b, float a = 1)
|
||||
: R(r)
|
||||
, G(g)
|
||||
, B(b)
|
||||
@@ -203,7 +203,7 @@ public:
|
||||
return Color(R - b.R, G - b.G, B - b.B, A - b.A);
|
||||
}
|
||||
|
||||
Color operator*(const Color& b) const
|
||||
FORCE_INLINE Color operator*(const Color& b) const
|
||||
{
|
||||
return Color(R * b.R, G * b.G, B * b.B, A * b.A);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Half.h"
|
||||
#include "Rectangle.h"
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
#include "Vector4.h"
|
||||
#include "Rectangle.h"
|
||||
#include "Color.h"
|
||||
|
||||
static_assert(sizeof(Half) == 2, "Invalid Half type size.");
|
||||
@@ -16,12 +14,47 @@ Half2 Half2::Zero(0.0f, 0.0f);
|
||||
Half3 Half3::Zero(0.0f, 0.0f, 0.0f);
|
||||
Half4 Half4::Zero(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
||||
Half2::Half2(const Float2& v)
|
||||
#if !USE_SSE_HALF_CONVERSION
|
||||
|
||||
Half Float16Compressor::Compress(float value)
|
||||
{
|
||||
X = Float16Compressor::Compress(v.X);
|
||||
Y = Float16Compressor::Compress(v.Y);
|
||||
Bits v, s;
|
||||
v.f = value;
|
||||
uint32 sign = v.si & signN;
|
||||
v.si ^= sign;
|
||||
sign >>= shiftSign; // logical shift
|
||||
s.si = mulN;
|
||||
s.si = static_cast<int32>(s.f * v.f); // correct subnormals
|
||||
v.si ^= (s.si ^ v.si) & -(minN > v.si);
|
||||
v.si ^= (infN ^ v.si) & -((infN > v.si) & (v.si > maxN));
|
||||
v.si ^= (nanN ^ v.si) & -((nanN > v.si) & (v.si > infN));
|
||||
v.ui >>= shift; // logical shift
|
||||
v.si ^= ((v.si - maxD) ^ v.si) & -(v.si > maxC);
|
||||
v.si ^= ((v.si - minD) ^ v.si) & -(v.si > subC);
|
||||
return v.ui | sign;
|
||||
}
|
||||
|
||||
float Float16Compressor::Decompress(Half value)
|
||||
{
|
||||
Bits v;
|
||||
v.ui = value;
|
||||
int32 sign = v.si & signC;
|
||||
v.si ^= sign;
|
||||
sign <<= shiftSign;
|
||||
v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC);
|
||||
v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC);
|
||||
Bits s;
|
||||
s.si = mulC;
|
||||
s.f *= v.si;
|
||||
const int32 mask = -(norC > v.si);
|
||||
v.si <<= shift;
|
||||
v.si ^= (s.si ^ v.si) & mask;
|
||||
v.si |= sign;
|
||||
return v.f;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Float2 Half2::ToFloat2() const
|
||||
{
|
||||
return Float2(
|
||||
@@ -30,13 +63,6 @@ Float2 Half2::ToFloat2() const
|
||||
);
|
||||
}
|
||||
|
||||
Half3::Half3(const Float3& v)
|
||||
{
|
||||
X = Float16Compressor::Compress(v.X);
|
||||
Y = Float16Compressor::Compress(v.Y);
|
||||
Z = Float16Compressor::Compress(v.Z);
|
||||
}
|
||||
|
||||
Float3 Half3::ToFloat3() const
|
||||
{
|
||||
return Float3(
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Math.h"
|
||||
#include "Vector2.h"
|
||||
#include "Vector3.h"
|
||||
|
||||
/// <summary>
|
||||
/// Half-precision 16 bit floating point number consisting of a sign bit, a 5 bit biased exponent, and a 10 bit mantissa
|
||||
@@ -45,54 +47,23 @@ class FLAXENGINE_API Float16Compressor
|
||||
static const int32 minD = minC - subC - 1;
|
||||
|
||||
public:
|
||||
static Half Compress(const float value)
|
||||
{
|
||||
#if USE_SSE_HALF_CONVERSION
|
||||
FORCE_INLINE static Half Compress(float value)
|
||||
{
|
||||
__m128 value1 = _mm_set_ss(value);
|
||||
__m128i value2 = _mm_cvtps_ph(value1, 0);
|
||||
return static_cast<Half>(_mm_cvtsi128_si32(value2));
|
||||
#else
|
||||
Bits v, s;
|
||||
v.f = value;
|
||||
uint32 sign = v.si & signN;
|
||||
v.si ^= sign;
|
||||
sign >>= shiftSign; // logical shift
|
||||
s.si = mulN;
|
||||
s.si = static_cast<int32>(s.f * v.f); // correct subnormals
|
||||
v.si ^= (s.si ^ v.si) & -(minN > v.si);
|
||||
v.si ^= (infN ^ v.si) & -((infN > v.si) & (v.si > maxN));
|
||||
v.si ^= (nanN ^ v.si) & -((nanN > v.si) & (v.si > infN));
|
||||
v.ui >>= shift; // logical shift
|
||||
v.si ^= ((v.si - maxD) ^ v.si) & -(v.si > maxC);
|
||||
v.si ^= ((v.si - minD) ^ v.si) & -(v.si > subC);
|
||||
return v.ui | sign;
|
||||
#endif
|
||||
}
|
||||
|
||||
static float Decompress(const Half value)
|
||||
FORCE_INLINE static float Decompress(Half value)
|
||||
{
|
||||
#if USE_SSE_HALF_CONVERSION
|
||||
__m128i value1 = _mm_cvtsi32_si128(static_cast<int>(value));
|
||||
__m128 value2 = _mm_cvtph_ps(value1);
|
||||
return _mm_cvtss_f32(value2);
|
||||
#else
|
||||
Bits v;
|
||||
v.ui = value;
|
||||
int32 sign = v.si & signC;
|
||||
v.si ^= sign;
|
||||
sign <<= shiftSign;
|
||||
v.si ^= ((v.si + minD) ^ v.si) & -(v.si > subC);
|
||||
v.si ^= ((v.si + maxD) ^ v.si) & -(v.si > maxC);
|
||||
Bits s;
|
||||
s.si = mulC;
|
||||
s.f *= v.si;
|
||||
const int32 mask = -(norC > v.si);
|
||||
v.si <<= shift;
|
||||
v.si ^= (s.si ^ v.si) & mask;
|
||||
v.si |= sign;
|
||||
return v.f;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static Half Compress(float value);
|
||||
static float Decompress(Half value);
|
||||
#endif
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -128,7 +99,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="x">X component</param>
|
||||
/// <param name="y">Y component</param>
|
||||
Half2(Half x, Half y)
|
||||
FORCE_INLINE Half2(Half x, Half y)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
{
|
||||
@@ -139,7 +110,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="x">X component</param>
|
||||
/// <param name="y">Y component</param>
|
||||
Half2(float x, float y)
|
||||
FORCE_INLINE Half2(float x, float y)
|
||||
{
|
||||
X = Float16Compressor::Compress(x);
|
||||
Y = Float16Compressor::Compress(y);
|
||||
@@ -149,7 +120,11 @@ public:
|
||||
/// Init
|
||||
/// </summary>
|
||||
/// <param name="v">X and Y components</param>
|
||||
Half2(const Float2& v);
|
||||
FORCE_INLINE Half2(const Float2& v)
|
||||
{
|
||||
X = Float16Compressor::Compress(v.X);
|
||||
Y = Float16Compressor::Compress(v.Y);
|
||||
}
|
||||
|
||||
public:
|
||||
Float2 ToFloat2() const;
|
||||
@@ -185,21 +160,26 @@ public:
|
||||
public:
|
||||
Half3() = default;
|
||||
|
||||
Half3(Half x, Half y, Half z)
|
||||
FORCE_INLINE Half3(Half x, Half y, Half z)
|
||||
: X(x)
|
||||
, Y(y)
|
||||
, Z(z)
|
||||
{
|
||||
}
|
||||
|
||||
Half3(const float x, const float y, const float z)
|
||||
FORCE_INLINE Half3(float x, float y, float z)
|
||||
{
|
||||
X = Float16Compressor::Compress(x);
|
||||
Y = Float16Compressor::Compress(y);
|
||||
Z = Float16Compressor::Compress(z);
|
||||
}
|
||||
|
||||
Half3(const Float3& v);
|
||||
FORCE_INLINE Half3(const Float3& v)
|
||||
{
|
||||
X = Float16Compressor::Compress(v.X);
|
||||
Y = Float16Compressor::Compress(v.Y);
|
||||
Z = Float16Compressor::Compress(v.Z);
|
||||
}
|
||||
|
||||
public:
|
||||
Float3 ToFloat3() const;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "Collections/Dictionary.h"
|
||||
#include "Engine/Engine/Time.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
|
||||
@@ -14,16 +13,15 @@ const Char* HertzSizesData[] = { TEXT("Hz"), TEXT("KHz"), TEXT("MHz"), TEXT("GHz
|
||||
Span<const Char*> Utilities::Private::BytesSizes(BytesSizesData, ARRAY_COUNT(BytesSizesData));
|
||||
Span<const Char*> Utilities::Private::HertzSizes(HertzSizesData, ARRAY_COUNT(HertzSizesData));
|
||||
|
||||
namespace ObjectsRemovalServiceImpl
|
||||
namespace
|
||||
{
|
||||
CriticalSection PoolLocker;
|
||||
DateTime LastUpdate;
|
||||
float LastUpdateGameTime;
|
||||
Dictionary<Object*, float> Pool(8192);
|
||||
uint64 PoolCounter = 0;
|
||||
}
|
||||
|
||||
using namespace ObjectsRemovalServiceImpl;
|
||||
|
||||
class ObjectsRemoval : public EngineService
|
||||
{
|
||||
public:
|
||||
@@ -64,6 +62,7 @@ void ObjectsRemovalService::Add(Object* obj, float timeToLive, bool useGameTime)
|
||||
|
||||
PoolLocker.Lock();
|
||||
Pool[obj] = timeToLive;
|
||||
PoolCounter++;
|
||||
PoolLocker.Unlock();
|
||||
}
|
||||
|
||||
@@ -72,6 +71,7 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta)
|
||||
PROFILE_CPU();
|
||||
|
||||
PoolLocker.Lock();
|
||||
PoolCounter = 0;
|
||||
|
||||
// Update timeouts and delete objects that timed out
|
||||
for (auto i = Pool.Begin(); i.IsNotEnd(); ++i)
|
||||
@@ -90,6 +90,24 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta)
|
||||
}
|
||||
}
|
||||
|
||||
// If any object was added to the pool while removing objects (by this thread) then retry removing any nested objects (but without delta time)
|
||||
if (PoolCounter != 0)
|
||||
{
|
||||
RETRY:
|
||||
PoolCounter = 0;
|
||||
for (auto i = Pool.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
if (i->Value <= 0.0f)
|
||||
{
|
||||
Object* obj = i->Key;
|
||||
Pool.Remove(i);
|
||||
obj->OnDeleteObject();
|
||||
}
|
||||
}
|
||||
if (PoolCounter != 0)
|
||||
goto RETRY;
|
||||
}
|
||||
|
||||
PoolLocker.Unlock();
|
||||
}
|
||||
|
||||
@@ -121,7 +139,7 @@ void ObjectsRemoval::Dispose()
|
||||
|
||||
// Delete all remaining objects
|
||||
{
|
||||
ScopeLock lock(PoolLocker);
|
||||
PoolLocker.Lock();
|
||||
for (auto i = Pool.Begin(); i.IsNotEnd(); ++i)
|
||||
{
|
||||
Object* obj = i->Key;
|
||||
@@ -129,6 +147,7 @@ void ObjectsRemoval::Dispose()
|
||||
obj->OnDeleteObject();
|
||||
}
|
||||
Pool.Clear();
|
||||
PoolLocker.Unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -857,36 +857,25 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, IntPtr valuePtr)
|
||||
internal static void FieldGetValueReference(ManagedHandle fieldOwnerHandle, ManagedHandle fieldHandle, int fieldOffset, IntPtr valuePtr)
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
IntPtr fieldRef;
|
||||
#if USE_AOT
|
||||
FieldHolder field = Unsafe.As<FieldHolder>(fieldHandle.Target);
|
||||
fieldRef = IntPtr.Zero;
|
||||
Debug.LogError("Not supported FieldGetValueReference");
|
||||
#else
|
||||
if (fieldOwner.GetType().IsValueType)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
fieldRef = FieldHelper.GetValueTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(field.fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
internal static void FieldGetValueReferenceWithOffset(ManagedHandle fieldOwnerHandle, int fieldOffset, IntPtr valuePtr)
|
||||
{
|
||||
object fieldOwner = fieldOwnerHandle.Target;
|
||||
if (fieldOwner.GetType().IsValueType)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetValueTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
fieldRef = FieldHelper.GetReferenceTypeFieldReference<object, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
}
|
||||
#endif
|
||||
Unsafe.Write<IntPtr>(valuePtr.ToPointer(), fieldRef);
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly]
|
||||
|
||||
@@ -119,6 +119,7 @@ namespace FlaxEngine.Interop
|
||||
{
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
// Cache offsets to frequently accessed fields of FlaxEngine.Object
|
||||
private static int unmanagedPtrFieldOffset = IntPtr.Size + (Unsafe.Read<int>((typeof(FlaxEngine.Object).GetField("__unmanagedPtr", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF);
|
||||
private static int internalIdFieldOffset = IntPtr.Size + (Unsafe.Read<int>((typeof(FlaxEngine.Object).GetField("__internalId", BindingFlags.Instance | BindingFlags.NonPublic).FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF);
|
||||
@@ -150,6 +151,7 @@ namespace FlaxEngine.Interop
|
||||
object obj = typeHolder.CreateScriptingObject(unmanagedPtr, idPtr);
|
||||
return ManagedHandle.Alloc(obj);
|
||||
}
|
||||
#endif
|
||||
|
||||
internal static void* NativeAlloc(int byteCount)
|
||||
{
|
||||
@@ -429,6 +431,9 @@ namespace FlaxEngine.Interop
|
||||
/// </summary>
|
||||
internal static int GetFieldOffset(FieldInfo field, Type type)
|
||||
{
|
||||
if (field.IsLiteral)
|
||||
return 0;
|
||||
|
||||
// Get the address of the field, source: https://stackoverflow.com/a/56512720
|
||||
int fieldOffset = Unsafe.Read<int>((field.FieldHandle.Value + 4 + IntPtr.Size).ToPointer()) & 0xFFFFFF;
|
||||
if (!type.IsValueType)
|
||||
@@ -436,6 +441,23 @@ namespace FlaxEngine.Interop
|
||||
return fieldOffset;
|
||||
}
|
||||
|
||||
#if USE_AOT
|
||||
/// <summary>
|
||||
/// Helper utility to set field of the referenced value via reflection.
|
||||
/// </summary>
|
||||
internal static void SetReferenceTypeField<T>(FieldInfo field, ref T fieldOwner, object fieldValue)
|
||||
{
|
||||
if (typeof(T).IsValueType)
|
||||
{
|
||||
// Value types need setting via boxed object to properly propagate value
|
||||
object fieldOwnerBoxed = fieldOwner;
|
||||
field.SetValue(fieldOwnerBoxed, fieldValue);
|
||||
fieldOwner = (T)fieldOwnerBoxed;
|
||||
}
|
||||
else
|
||||
field.SetValue(fieldOwner, fieldValue);
|
||||
}
|
||||
#else
|
||||
/// <summary>
|
||||
/// Returns a reference to the value of the field.
|
||||
/// </summary>
|
||||
@@ -462,6 +484,7 @@ namespace FlaxEngine.Interop
|
||||
byte* fieldPtr = (byte*)Unsafe.As<T, IntPtr>(ref fieldOwner) + fieldOffset;
|
||||
return ref Unsafe.AsRef<TField>(fieldPtr);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -735,29 +758,49 @@ namespace FlaxEngine.Interop
|
||||
|
||||
private static void ToManagedFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
{
|
||||
#if USE_AOT
|
||||
IntPtr fieldValue = Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer());
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#else
|
||||
ref IntPtr fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
fieldValueRef = Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer());
|
||||
#endif
|
||||
fieldSize = IntPtr.Size;
|
||||
}
|
||||
|
||||
private static void ToManagedFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
{
|
||||
#if USE_AOT
|
||||
IntPtr fieldValue = Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer());
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#else
|
||||
ref IntPtr fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
fieldValueRef = Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer());
|
||||
#endif
|
||||
fieldSize = IntPtr.Size;
|
||||
}
|
||||
|
||||
private static void ToNativeFieldPointerValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
{
|
||||
ref IntPtr fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(nativeFieldPtr.ToPointer(), fieldValueRef);
|
||||
#if USE_AOT
|
||||
object boxed = field.GetValue(fieldOwner);
|
||||
IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed));
|
||||
#else
|
||||
IntPtr fieldValue = FieldHelper.GetValueTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
Unsafe.Write<IntPtr>(nativeFieldPtr.ToPointer(), fieldValue);
|
||||
fieldSize = IntPtr.Size;
|
||||
}
|
||||
|
||||
private static void ToNativeFieldPointerReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
{
|
||||
ref IntPtr fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
Unsafe.Write<IntPtr>(nativeFieldPtr.ToPointer(), fieldValueRef);
|
||||
#if USE_AOT
|
||||
object boxed = field.GetValue(fieldOwner);
|
||||
IntPtr fieldValue = new IntPtr(Pointer.Unbox(boxed));
|
||||
#else
|
||||
IntPtr fieldValue = FieldHelper.GetReferenceTypeFieldReference<T, IntPtr>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
Unsafe.Write<IntPtr>(nativeFieldPtr.ToPointer(), fieldValue);
|
||||
fieldSize = IntPtr.Size;
|
||||
}
|
||||
|
||||
@@ -799,8 +842,15 @@ namespace FlaxEngine.Interop
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
}
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValueRef, nativeFieldPtr, false);
|
||||
#if USE_AOT
|
||||
TField fieldValue = default;
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValue, nativeFieldPtr, false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -813,8 +863,15 @@ namespace FlaxEngine.Interop
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
}
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValueRef, nativeFieldPtr, false);
|
||||
#if USE_AOT
|
||||
TField fieldValue = default;
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValue, nativeFieldPtr, false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldArrayValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
@@ -825,8 +882,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField[] fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField[] fieldValue = (TField[])field.GetValue(fieldOwner);
|
||||
#else
|
||||
ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldArrayReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -837,8 +901,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField[] fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField[] fieldValue = null;
|
||||
#else
|
||||
ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToNativeFieldValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
@@ -852,11 +923,11 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
#if USE_AOT
|
||||
TField fieldValueRef = (TField)field.GetValue(fieldOwner);
|
||||
TField fieldValue = (TField)field.GetValue(fieldOwner);
|
||||
#else
|
||||
ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToNative(ref fieldValueRef, nativeFieldPtr);
|
||||
MarshalHelper<TField>.ToNative(ref fieldValue, nativeFieldPtr);
|
||||
}
|
||||
|
||||
internal static void ToNativeFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -870,11 +941,11 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
|
||||
#if USE_AOT
|
||||
TField fieldValueRef = (TField)field.GetValue(fieldOwner);
|
||||
TField fieldValue = (TField)field.GetValue(fieldOwner);
|
||||
#else
|
||||
ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToNative(ref fieldValueRef, nativeFieldPtr);
|
||||
MarshalHelper<TField>.ToNative(ref fieldValue, nativeFieldPtr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,8 +975,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField fieldValue = null;
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -915,8 +993,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField fieldValue = default;
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldArrayValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
@@ -926,8 +1011,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField[] fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField[] fieldValue = null;
|
||||
#else
|
||||
ref TField[] fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToManagedFieldArrayReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -937,8 +1029,15 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField[] fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValueRef, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
TField[] fieldValue = null;
|
||||
#else
|
||||
ref TField[] fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField[]>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField[]>.ToManaged(ref fieldValue, Unsafe.Read<IntPtr>(nativeFieldPtr.ToPointer()), false);
|
||||
#if USE_AOT
|
||||
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, fieldValue);
|
||||
#endif
|
||||
}
|
||||
|
||||
internal static void ToNativeFieldValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||
@@ -948,8 +1047,12 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToNative(ref fieldValueRef, nativeFieldPtr);
|
||||
#if USE_AOT
|
||||
TField fieldValue = (TField)field.GetValue(fieldOwner);
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetValueTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToNative(ref fieldValue, nativeFieldPtr);
|
||||
}
|
||||
|
||||
internal static void ToNativeFieldReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||
@@ -959,8 +1062,12 @@ namespace FlaxEngine.Interop
|
||||
nativeFieldPtr = EnsureAlignment(nativeFieldPtr, IntPtr.Size);
|
||||
fieldSize += (nativeFieldPtr - fieldStartPtr).ToInt32();
|
||||
|
||||
ref TField fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
MarshalHelper<TField>.ToNative(ref fieldValueRef, nativeFieldPtr);
|
||||
#if USE_AOT
|
||||
TField fieldValue = (TField)field.GetValue(fieldOwner);
|
||||
#else
|
||||
ref TField fieldValue = ref FieldHelper.GetReferenceTypeFieldReference<T, TField>(fieldOffset, ref fieldOwner);
|
||||
#endif
|
||||
MarshalHelper<TField>.ToNative(ref fieldValue, nativeFieldPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1044,7 +1151,7 @@ namespace FlaxEngine.Interop
|
||||
var fields = MarshalHelper<T>.marshallableFields;
|
||||
var offsets = MarshalHelper<T>.marshallableFieldOffsets;
|
||||
var marshallers = MarshalHelper<T>.toNativeFieldMarshallers;
|
||||
for (int i = 0; i < MarshalHelper<T>.marshallableFields.Length; i++)
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize);
|
||||
nativePtr += fieldSize;
|
||||
@@ -1306,11 +1413,13 @@ namespace FlaxEngine.Interop
|
||||
return RuntimeHelpers.GetUninitializedObject(wrappedType);
|
||||
}
|
||||
|
||||
#if !USE_AOT
|
||||
internal object CreateScriptingObject(IntPtr unmanagedPtr, IntPtr idPtr)
|
||||
{
|
||||
object obj = CreateObject();
|
||||
object obj = RuntimeHelpers.GetUninitializedObject(wrappedType);
|
||||
if (obj is Object)
|
||||
{
|
||||
// TODO: use UnsafeAccessorAttribute on .NET 8 and use this path on all platforms (including non-Desktop, see MCore::ScriptingObject::CreateScriptingObject)
|
||||
{
|
||||
ref IntPtr fieldRef = ref FieldHelper.GetReferenceTypeFieldReference<IntPtr>(unmanagedPtrFieldOffset, ref obj);
|
||||
fieldRef = unmanagedPtr;
|
||||
@@ -1331,8 +1440,9 @@ namespace FlaxEngine.Interop
|
||||
|
||||
return obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static implicit operator Type(TypeHolder holder) => holder?.type ?? null;
|
||||
public static implicit operator Type(TypeHolder holder) => holder?.type;
|
||||
public bool Equals(TypeHolder other) => type == other.type;
|
||||
public bool Equals(Type other) => type == other;
|
||||
public override int GetHashCode() => type.GetHashCode();
|
||||
|
||||
@@ -259,6 +259,11 @@ API_STRUCT() struct GPULimits
|
||||
/// </summary>
|
||||
API_FIELD() bool HasDepthAsSRV;
|
||||
|
||||
/// <summary>
|
||||
/// True if device supports depth buffer clipping (see GPUPipelineState::Description::DepthClipEnable).
|
||||
/// </summary>
|
||||
API_FIELD() bool HasDepthClip;
|
||||
|
||||
/// <summary>
|
||||
/// True if device supports depth buffer texture as a readonly depth buffer (can be sampled in the shader while performing depth-test).
|
||||
/// </summary>
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, int[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
@@ -357,7 +357,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(List<Vector3> vertices, List<int> triangles, List<Vector3> normals = null, List<Vector3> tangents = null, List<Vector2> uv = null, List<Color32> colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
@@ -375,7 +375,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, uint[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
@@ -393,7 +393,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(List<Vector3> vertices, List<uint> triangles, List<Vector3> normals = null, List<Vector3> tangents = null, List<Vector2> uv = null, List<Color32> colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
@@ -411,7 +411,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, ushort[] triangles, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null, Color32[] colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
@@ -429,7 +429,7 @@ namespace FlaxEngine
|
||||
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
/// <param name="colors">The vertex colors (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(List<Vector3> vertices, List<ushort> triangles, List<Vector3> normals = null, List<Vector3> tangents = null, List<Vector2> uv = null, List<Color32> colors = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv), colors);
|
||||
|
||||
@@ -216,7 +216,7 @@ namespace FlaxEngine
|
||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, int[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv));
|
||||
@@ -235,7 +235,7 @@ namespace FlaxEngine
|
||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||
/// <param name="tangents">The normal vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, uint[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv));
|
||||
@@ -254,7 +254,7 @@ namespace FlaxEngine
|
||||
/// <param name="normals">The normal vectors (per vertex).</param>
|
||||
/// <param name="tangents">The tangent vectors (per vertex). Use null to compute them from normal vectors.</param>
|
||||
/// <param name="uv">The texture coordinates (per vertex).</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void UpdateMesh(Vector3[] vertices, ushort[] triangles, Int4[] blendIndices, Vector4[] blendWeights, Vector3[] normals = null, Vector3[] tangents = null, Vector2[] uv = null)
|
||||
{
|
||||
UpdateMesh(Utils.ConvertCollection(vertices), triangles, blendIndices, Utils.ConvertCollection(blendWeights), Utils.ConvertCollection(normals), Utils.ConvertCollection(tangents), Utils.ConvertCollection(uv));
|
||||
|
||||
@@ -359,6 +359,7 @@ bool GPUDeviceDX11::Init()
|
||||
limits.HasAppendConsumeBuffers = true;
|
||||
limits.HasSeparateRenderTargetBlendState = true;
|
||||
limits.HasDepthAsSRV = true;
|
||||
limits.HasDepthClip = true;
|
||||
limits.HasReadOnlyDepth = true;
|
||||
limits.HasMultisampleDepthAsSRV = true;
|
||||
limits.HasTypedUAVLoad = featureDataD3D11Options2.TypedUAVLoadAdditionalFormats != 0;
|
||||
@@ -382,6 +383,7 @@ bool GPUDeviceDX11::Init()
|
||||
limits.HasAppendConsumeBuffers = false;
|
||||
limits.HasSeparateRenderTargetBlendState = false;
|
||||
limits.HasDepthAsSRV = false;
|
||||
limits.HasDepthClip = true;
|
||||
limits.HasReadOnlyDepth = createdFeatureLevel == D3D_FEATURE_LEVEL_10_1;
|
||||
limits.HasMultisampleDepthAsSRV = false;
|
||||
limits.HasTypedUAVLoad = false;
|
||||
|
||||
@@ -381,6 +381,7 @@ bool GPUDeviceDX12::Init()
|
||||
limits.HasAppendConsumeBuffers = true;
|
||||
limits.HasSeparateRenderTargetBlendState = true;
|
||||
limits.HasDepthAsSRV = true;
|
||||
limits.HasDepthClip = true;
|
||||
limits.HasReadOnlyDepth = true;
|
||||
limits.HasMultisampleDepthAsSRV = true;
|
||||
limits.HasTypedUAVLoad = options.TypedUAVLoadAdditionalFormats != 0;
|
||||
|
||||
@@ -50,18 +50,7 @@ bool GPUDeviceNull::Init()
|
||||
// Init device limits
|
||||
{
|
||||
auto& limits = Limits;
|
||||
limits.HasCompute = false;
|
||||
limits.HasTessellation = false;
|
||||
limits.HasGeometryShaders = false;
|
||||
limits.HasInstancing = false;
|
||||
limits.HasVolumeTextureRendering = false;
|
||||
limits.HasDrawIndirect = false;
|
||||
limits.HasAppendConsumeBuffers = false;
|
||||
limits.HasSeparateRenderTargetBlendState = false;
|
||||
limits.HasDepthAsSRV = false;
|
||||
limits.HasReadOnlyDepth = false;
|
||||
limits.HasMultisampleDepthAsSRV = false;
|
||||
limits.HasTypedUAVLoad = false;
|
||||
Platform::MemoryClear(&limits, sizeof(limits));
|
||||
limits.MaximumMipLevelsCount = 14;
|
||||
limits.MaximumTexture1DSize = 8192;
|
||||
limits.MaximumTexture1DArraySize = 512;
|
||||
@@ -70,11 +59,8 @@ bool GPUDeviceNull::Init()
|
||||
limits.MaximumTexture3DSize = 2048;
|
||||
limits.MaximumTextureCubeSize = 16384;
|
||||
limits.MaximumSamplerAnisotropy = 1;
|
||||
|
||||
for (int32 i = 0; i < static_cast<int32>(PixelFormat::MAX); i++)
|
||||
{
|
||||
FeaturesPerFormat[i] = FormatFeatures(static_cast<PixelFormat>(i), MSAALevel::None, FormatSupport::None);
|
||||
}
|
||||
}
|
||||
|
||||
// Create main context
|
||||
|
||||
@@ -1210,16 +1210,16 @@ void GPUContextVulkan::ResolveMultisample(GPUTexture* sourceMultisampleTexture,
|
||||
|
||||
void GPUContextVulkan::DrawInstanced(uint32 verticesCount, uint32 instanceCount, int32 startInstance, int32 startVertex)
|
||||
{
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
OnDrawCall();
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
vkCmdDraw(cmdBuffer->GetHandle(), verticesCount, instanceCount, startVertex, startInstance);
|
||||
RENDER_STAT_DRAW_CALL(verticesCount * instanceCount, verticesCount * instanceCount / 3);
|
||||
}
|
||||
|
||||
void GPUContextVulkan::DrawIndexedInstanced(uint32 indicesCount, uint32 instanceCount, int32 startInstance, int32 startVertex, int32 startIndex)
|
||||
{
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
OnDrawCall();
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
vkCmdDrawIndexed(cmdBuffer->GetHandle(), indicesCount, instanceCount, startIndex, startVertex, startInstance);
|
||||
RENDER_STAT_DRAW_CALL(0, indicesCount / 3 * instanceCount);
|
||||
}
|
||||
@@ -1227,10 +1227,9 @@ void GPUContextVulkan::DrawIndexedInstanced(uint32 indicesCount, uint32 instance
|
||||
void GPUContextVulkan::DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs)
|
||||
{
|
||||
ASSERT(bufferForArgs && EnumHasAnyFlags(bufferForArgs->GetFlags(), GPUBufferFlags::Argument));
|
||||
|
||||
OnDrawCall();
|
||||
auto bufferForArgsVK = (GPUBufferVulkan*)bufferForArgs;
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
OnDrawCall();
|
||||
vkCmdDrawIndirect(cmdBuffer->GetHandle(), bufferForArgsVK->GetHandle(), (VkDeviceSize)offsetForArgs, 1, sizeof(VkDrawIndirectCommand));
|
||||
RENDER_STAT_DRAW_CALL(0, 0);
|
||||
}
|
||||
@@ -1238,10 +1237,9 @@ void GPUContextVulkan::DrawInstancedIndirect(GPUBuffer* bufferForArgs, uint32 of
|
||||
void GPUContextVulkan::DrawIndexedInstancedIndirect(GPUBuffer* bufferForArgs, uint32 offsetForArgs)
|
||||
{
|
||||
ASSERT(bufferForArgs && EnumHasAnyFlags(bufferForArgs->GetFlags(), GPUBufferFlags::Argument));
|
||||
|
||||
OnDrawCall();
|
||||
auto bufferForArgsVK = (GPUBufferVulkan*)bufferForArgs;
|
||||
const auto cmdBuffer = _cmdBufferManager->GetCmdBuffer();
|
||||
OnDrawCall();
|
||||
vkCmdDrawIndexedIndirect(cmdBuffer->GetHandle(), bufferForArgsVK->GetHandle(), (VkDeviceSize)offsetForArgs, 1, sizeof(VkDrawIndexedIndirectCommand));
|
||||
RENDER_STAT_DRAW_CALL(0, 0);
|
||||
}
|
||||
|
||||
@@ -1704,6 +1704,7 @@ bool GPUDeviceVulkan::Init()
|
||||
limits.HasDrawIndirect = PhysicalDeviceLimits.maxDrawIndirectCount >= 1;
|
||||
limits.HasAppendConsumeBuffers = false; // TODO: add Append Consume buffers support for Vulkan
|
||||
limits.HasSeparateRenderTargetBlendState = true;
|
||||
limits.HasDepthClip = PhysicalDeviceFeatures.depthClamp;
|
||||
limits.HasDepthAsSRV = true;
|
||||
limits.HasReadOnlyDepth = true;
|
||||
limits.HasMultisampleDepthAsSRV = !!PhysicalDeviceFeatures.sampleRateShading;
|
||||
|
||||
@@ -340,7 +340,7 @@ bool GPUPipelineStateVulkan::Init(const Description& desc)
|
||||
break;
|
||||
}
|
||||
_descRasterization.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
_descRasterization.depthClampEnable = !desc.DepthClipEnable;
|
||||
_descRasterization.depthClampEnable = !desc.DepthClipEnable && _device->Limits.HasDepthClip;
|
||||
_descRasterization.lineWidth = 1.0f;
|
||||
_desc.pRasterizationState = &_descRasterization;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ void GPUTimerQueryVulkan::Interrupt(CmdBufferVulkan* cmdBuffer)
|
||||
if (!_interrupted)
|
||||
{
|
||||
_interrupted = true;
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End);
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ void GPUTimerQueryVulkan::Resume(CmdBufferVulkan* cmdBuffer)
|
||||
e.End.Pool = nullptr;
|
||||
|
||||
_interrupted = false;
|
||||
WriteTimestamp(cmdBuffer, e.Begin);
|
||||
WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
|
||||
_queries.Add(e);
|
||||
_queryIndex++;
|
||||
@@ -56,13 +56,13 @@ bool GPUTimerQueryVulkan::GetResult(Query& query)
|
||||
return false;
|
||||
}
|
||||
|
||||
void GPUTimerQueryVulkan::WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query) const
|
||||
void GPUTimerQueryVulkan::WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const
|
||||
{
|
||||
auto pool = _device->FindAvailableTimestampQueryPool();
|
||||
uint32 index;
|
||||
pool->AcquireQuery(index);
|
||||
|
||||
vkCmdWriteTimestamp(cmdBuffer->GetHandle(), VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, pool->GetHandle(), index);
|
||||
vkCmdWriteTimestamp(cmdBuffer->GetHandle(), stage, pool->GetHandle(), index);
|
||||
pool->MarkQueryAsStarted(index);
|
||||
|
||||
query.Pool = pool;
|
||||
@@ -168,7 +168,7 @@ void GPUTimerQueryVulkan::Begin()
|
||||
|
||||
_queryIndex = 0;
|
||||
_interrupted = false;
|
||||
WriteTimestamp(cmdBuffer, e.Begin);
|
||||
WriteTimestamp(cmdBuffer, e.Begin, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT);
|
||||
context->GetCmdBufferManager()->OnQueryBegin(this);
|
||||
|
||||
ASSERT(_queries.IsEmpty());
|
||||
@@ -193,7 +193,7 @@ void GPUTimerQueryVulkan::End()
|
||||
|
||||
if (!_interrupted)
|
||||
{
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End);
|
||||
WriteTimestamp(cmdBuffer, _queries[_queryIndex].End, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
|
||||
}
|
||||
context->GetCmdBufferManager()->OnQueryEnd(this);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ public:
|
||||
private:
|
||||
|
||||
bool GetResult(Query& query);
|
||||
void WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query) const;
|
||||
void WriteTimestamp(CmdBufferVulkan* cmdBuffer, Query& query, VkPipelineStageFlagBits stage) const;
|
||||
bool TryGetResult();
|
||||
bool UseQueries();
|
||||
|
||||
|
||||
@@ -258,18 +258,32 @@ void NetworkReplicationService::Dispose()
|
||||
|
||||
NetworkReplicationService NetworkReplicationServiceInstance;
|
||||
|
||||
void INetworkSerializable_Serialize(void* instance, NetworkStream* stream, void* tag)
|
||||
void INetworkSerializable_Native_Serialize(void* instance, NetworkStream* stream, void* tag)
|
||||
{
|
||||
const int16 vtableOffset = (int16)(intptr)tag;
|
||||
((INetworkSerializable*)((byte*)instance + vtableOffset))->Serialize(stream);
|
||||
}
|
||||
|
||||
void INetworkSerializable_Deserialize(void* instance, NetworkStream* stream, void* tag)
|
||||
void INetworkSerializable_Native_Deserialize(void* instance, NetworkStream* stream, void* tag)
|
||||
{
|
||||
const int16 vtableOffset = (int16)(intptr)tag;
|
||||
((INetworkSerializable*)((byte*)instance + vtableOffset))->Deserialize(stream);
|
||||
}
|
||||
|
||||
void INetworkSerializable_Script_Serialize(void* instance, NetworkStream* stream, void* tag)
|
||||
{
|
||||
auto obj = (ScriptingObject*)instance;
|
||||
auto interface = ScriptingObject::ToInterface<INetworkSerializable>(obj);
|
||||
interface->Serialize(stream);
|
||||
}
|
||||
|
||||
void INetworkSerializable_Script_Deserialize(void* instance, NetworkStream* stream, void* tag)
|
||||
{
|
||||
auto obj = (ScriptingObject*)instance;
|
||||
auto interface = ScriptingObject::ToInterface<INetworkSerializable>(obj);
|
||||
interface->Deserialize(stream);
|
||||
}
|
||||
|
||||
NetworkReplicatedObject* ResolveObject(Guid objectId)
|
||||
{
|
||||
auto it = Objects.Find(objectId);
|
||||
@@ -1064,9 +1078,21 @@ bool NetworkReplicator::InvokeSerializer(const ScriptingTypeHandle& typeHandle,
|
||||
const ScriptingType::InterfaceImplementation* interface = type.GetInterface(INetworkSerializable::TypeInitializer);
|
||||
if (interface)
|
||||
{
|
||||
serializer.Methods[0] = INetworkSerializable_Serialize;
|
||||
serializer.Methods[1] = INetworkSerializable_Deserialize;
|
||||
serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback
|
||||
if (interface->IsNative)
|
||||
{
|
||||
// Native interface (implemented in C++)
|
||||
serializer.Methods[0] = INetworkSerializable_Native_Serialize;
|
||||
serializer.Methods[1] = INetworkSerializable_Native_Deserialize;
|
||||
serializer.Tags[0] = serializer.Tags[1] = (void*)(intptr)interface->VTableOffset; // Pass VTableOffset to the callback
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generic interface (implemented in C# or elsewhere)
|
||||
ASSERT(type.Type == ScriptingTypes::Script);
|
||||
serializer.Methods[0] = INetworkSerializable_Script_Serialize;
|
||||
serializer.Methods[1] = INetworkSerializable_Script_Deserialize;
|
||||
serializer.Tags[0] = serializer.Tags[1] = nullptr;
|
||||
}
|
||||
SerializersTable.Add(typeHandle, serializer);
|
||||
}
|
||||
else if (const ScriptingTypeHandle baseTypeHandle = typeHandle.GetType().GetBaseType())
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace FlaxEngine
|
||||
/// <param name="convexFlags">The convex mesh generation flags.</param>
|
||||
/// <param name="convexVertexLimit">The convex mesh vertex limit. Use values in range [8;255]</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public bool CookCollision(CollisionDataType type, Vector3[] vertices, uint[] triangles, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255)
|
||||
{
|
||||
if (vertices == null)
|
||||
@@ -43,7 +43,7 @@ namespace FlaxEngine
|
||||
/// <param name="convexFlags">The convex mesh generation flags.</param>
|
||||
/// <param name="convexVertexLimit">The convex mesh vertex limit. Use values in range [8;255]</param>
|
||||
/// <returns>True if failed, otherwise false.</returns>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public bool CookCollision(CollisionDataType type, Vector3[] vertices, int[] triangles, ConvexMeshGenerationFlags convexFlags = ConvexMeshGenerationFlags.None, int convexVertexLimit = 255)
|
||||
{
|
||||
if (vertices == null)
|
||||
@@ -60,7 +60,7 @@ namespace FlaxEngine
|
||||
/// </summary>
|
||||
/// <param name="vertexBuffer">The output vertex buffer.</param>
|
||||
/// <param name="indexBuffer">The output index buffer.</param>
|
||||
[Obsolete("Deprecated in 1.4")]
|
||||
[Obsolete("Deprecated in 1.4, use overload with Float3 and Float2 parameters")]
|
||||
public void ExtractGeometry(out Vector3[] vertexBuffer, out int[] indexBuffer)
|
||||
{
|
||||
ExtractGeometry(out Float3[] tmp, out indexBuffer);
|
||||
|
||||
@@ -69,7 +69,30 @@ bool LinuxFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView&
|
||||
}
|
||||
FILE* f = popen(cmd, "r");
|
||||
char buf[2048];
|
||||
fgets(buf, ARRAY_COUNT(buf), f);
|
||||
char* writePointer = buf;
|
||||
int remainingCapacity = ARRAY_COUNT(buf);
|
||||
// make sure we read all output from kdialog
|
||||
while (remainingCapacity > 0 && fgets(writePointer, remainingCapacity, f))
|
||||
{
|
||||
int r = strlen(writePointer);
|
||||
writePointer += r;
|
||||
remainingCapacity -= r;
|
||||
}
|
||||
if (remainingCapacity <= 0)
|
||||
{
|
||||
LOG(Error, "You selected more files than an internal buffer can hold. Try selecting fewer files at a time.");
|
||||
// in case of an overflow we miss the closing null byte, add it after the rightmost linefeed
|
||||
while (*writePointer != '\n')
|
||||
{
|
||||
writePointer--;
|
||||
if (writePointer == buf)
|
||||
{
|
||||
*buf = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*(++writePointer) = 0;
|
||||
}
|
||||
int result = pclose(f);
|
||||
if (result != 0)
|
||||
{
|
||||
|
||||
@@ -108,8 +108,7 @@ WindowsWindow::WindowsWindow(const CreateWindowSettings& settings)
|
||||
style |= WS_BORDER | WS_CAPTION | WS_DLGFRAME | WS_SYSMENU | WS_THICKFRAME | WS_GROUP;
|
||||
#elif WINDOWS_USE_NEWER_BORDER_LESS
|
||||
if (settings.IsRegularWindow)
|
||||
style |= WS_THICKFRAME | WS_SYSMENU;
|
||||
style |= WS_CAPTION;
|
||||
style |= WS_THICKFRAME | WS_SYSMENU | WS_CAPTION;
|
||||
#endif
|
||||
exStyle |= WS_EX_WINDOWEDGE;
|
||||
}
|
||||
@@ -220,12 +219,6 @@ void WindowsWindow::Show()
|
||||
if (!_settings.HasBorder)
|
||||
{
|
||||
SetWindowPos(_handle, nullptr, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
|
||||
if (!_settings.IsRegularWindow && _settings.ShowAfterFirstPaint && _settings.StartPosition == WindowStartPosition::Manual)
|
||||
{
|
||||
int32 x = Math::TruncToInt(_settings.Position.X);
|
||||
int32 y = Math::TruncToInt(_settings.Position.Y);
|
||||
SetWindowPos(_handle, nullptr, x, y, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
#include "Engine/Graphics/GPUContext.h"
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Renderer/Lightmaps.h"
|
||||
#endif
|
||||
@@ -86,11 +87,12 @@ bool ShadowsPass::Init()
|
||||
const auto formatFeaturesTexture = GPUDevice::Instance->GetFormatFeatures(formatTexture);
|
||||
_supportsShadows = EnumHasAllFlags(formatFeaturesDepth.Support, FormatSupport::DepthStencil | FormatSupport::Texture2D)
|
||||
&& EnumHasAllFlags(formatFeaturesTexture.Support, FormatSupport::ShaderSample | FormatSupport::ShaderSampleComparison);
|
||||
// TODO: fallback to 32-bit shadow map format if 16-bit is not supported
|
||||
if (!_supportsShadows)
|
||||
{
|
||||
LOG(Warning, "GPU doesn't support shadows rendering");
|
||||
LOG(Warning, "Format: {0}, features support: {1}", (int32)SHADOW_MAPS_FORMAT, (uint32)formatFeaturesDepth.Support);
|
||||
LOG(Warning, "Format: {0}, features support: {1}", (int32)formatTexture, (uint32)formatFeaturesTexture.Support);
|
||||
LOG(Warning, "Format: {0}, features support: {1}", ScriptingEnum::ToString(SHADOW_MAPS_FORMAT), (uint32)formatFeaturesDepth.Support);
|
||||
LOG(Warning, "Format: {0}, features support: {1}", ScriptingEnum::ToString(formatTexture), (uint32)formatFeaturesTexture.Support);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -190,7 +190,6 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject*
|
||||
|
||||
DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects()
|
||||
{
|
||||
ASSERT(IsInMainThread());
|
||||
ObjectsRemovalService::Flush();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ManagedDictionary.h"
|
||||
|
||||
#if USE_CSHARP
|
||||
Dictionary<ManagedDictionary::KeyValueType, MTypeObject*> ManagedDictionary::CachedDictionaryTypes;
|
||||
#if !USE_MONO_AOT
|
||||
ManagedDictionary::MakeGenericTypeThunk ManagedDictionary::MakeGenericType;
|
||||
@@ -12,3 +15,4 @@ MMethod* ManagedDictionary::CreateInstance;
|
||||
MMethod* ManagedDictionary::AddDictionaryItem;
|
||||
MMethod* ManagedDictionary::GetDictionaryKeys;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -25,8 +25,8 @@ private:
|
||||
MonoAssembly* _monoAssembly = nullptr;
|
||||
MonoImage* _monoImage = nullptr;
|
||||
#elif USE_NETCORE
|
||||
StringAnsi _fullname;
|
||||
void* _handle = nullptr;
|
||||
StringAnsi _fullname;
|
||||
#endif
|
||||
MDomain* _domain;
|
||||
|
||||
@@ -50,6 +50,7 @@ public:
|
||||
/// <param name="name">The assembly name.</param>
|
||||
MAssembly(MDomain* domain, const StringAnsiView& name);
|
||||
|
||||
#if USE_NETCORE
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MAssembly"/> class.
|
||||
/// </summary>
|
||||
@@ -58,6 +59,7 @@ public:
|
||||
/// <param name="fullname">The assembly full name.</param>
|
||||
/// <param name="handle">The managed handle of the assembly.</param>
|
||||
MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle);
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Finalizes an instance of the <see cref="MAssembly"/> class.
|
||||
|
||||
@@ -48,18 +48,22 @@ MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name)
|
||||
{
|
||||
}
|
||||
|
||||
#if USE_NETCORE
|
||||
|
||||
MAssembly::MAssembly(MDomain* domain, const StringAnsiView& name, const StringAnsiView& fullname, void* handle)
|
||||
: _domain(domain)
|
||||
: _handle(handle)
|
||||
, _fullname(fullname)
|
||||
, _domain(domain)
|
||||
, _isLoaded(false)
|
||||
, _isLoading(false)
|
||||
, _hasCachedClasses(false)
|
||||
, _reloadCount(0)
|
||||
, _name(name)
|
||||
, _fullname(fullname)
|
||||
, _handle(handle)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
MAssembly::~MAssembly()
|
||||
{
|
||||
Unload();
|
||||
|
||||
@@ -41,12 +41,18 @@
|
||||
#include <mono/jit/mono-private-unstable.h>
|
||||
#include <mono/utils/mono-logger.h>
|
||||
#include <mono/metadata/assembly.h>
|
||||
#include <mono/metadata/appdomain.h>
|
||||
#include <mono/metadata/class.h>
|
||||
#include <mono/metadata/metadata.h>
|
||||
#include <mono/metadata/threads.h>
|
||||
#include <mono/metadata/reflection.h>
|
||||
#include <mono/metadata/mono-private-unstable.h>
|
||||
typedef char char_t;
|
||||
#define DOTNET_HOST_MONO_DEBUG 0
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
void* MonoAotModuleHandle = nullptr;
|
||||
#endif
|
||||
MonoDomain* MonoDomainHandle = nullptr;
|
||||
#else
|
||||
#error "Unknown .NET runtime host."
|
||||
#endif
|
||||
@@ -180,7 +186,7 @@ void* GetStaticMethodPointer(const String& methodName);
|
||||
/// Calls the managed static method in NativeInterop class with given parameters.
|
||||
/// </summary>
|
||||
template<typename RetType, typename... Args>
|
||||
inline RetType CallStaticMethodByName(const String& methodName, Args... args)
|
||||
FORCE_INLINE RetType CallStaticMethodByName(const String& methodName, Args... args)
|
||||
{
|
||||
typedef RetType (CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
|
||||
return ((fun)GetStaticMethodPointer(methodName))(args...);
|
||||
@@ -190,7 +196,7 @@ inline RetType CallStaticMethodByName(const String& methodName, Args... args)
|
||||
/// Calls the managed static method with given parameters.
|
||||
/// </summary>
|
||||
template<typename RetType, typename... Args>
|
||||
inline RetType CallStaticMethod(void* methodPtr, Args... args)
|
||||
FORCE_INLINE RetType CallStaticMethod(void* methodPtr, Args... args)
|
||||
{
|
||||
typedef RetType (CORECLR_DELEGATE_CALLTYPE* fun)(Args...);
|
||||
return ((fun)methodPtr)(args...);
|
||||
@@ -516,6 +522,12 @@ void MCore::GC::FreeMemory(void* ptr, bool coTaskMem)
|
||||
|
||||
void MCore::Thread::Attach()
|
||||
{
|
||||
#if DOTNET_HOST_MONO
|
||||
if (!IsInMainThread() && !mono_domain_get())
|
||||
{
|
||||
mono_thread_attach(MonoDomainHandle);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MCore::Thread::Exit()
|
||||
@@ -617,14 +629,33 @@ bool MCore::Type::IsReference(MType* type)
|
||||
|
||||
void MCore::ScriptingObject::SetInternalValues(MClass* klass, MObject* object, void* unmanagedPtr, const Guid* id)
|
||||
{
|
||||
#if PLATFORM_DESKTOP && !USE_MONO_AOT
|
||||
static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectSetInternalValues"));
|
||||
CallStaticMethod<void, MObject*, void*, const Guid*>(ScriptingObjectSetInternalValuesPtr, object, unmanagedPtr, id);
|
||||
#else
|
||||
const MField* monoUnmanagedPtrField = klass->GetField("__unmanagedPtr");
|
||||
if (monoUnmanagedPtrField)
|
||||
monoUnmanagedPtrField->SetValue(object, &unmanagedPtr);
|
||||
const MField* monoIdField = klass->GetField("__internalId");
|
||||
if (id != nullptr && monoIdField)
|
||||
monoIdField->SetValue(object, (void*)id);
|
||||
#endif
|
||||
}
|
||||
|
||||
MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unmanagedPtr, const Guid* id)
|
||||
{
|
||||
#if PLATFORM_DESKTOP && !USE_MONO_AOT
|
||||
static void* ScriptingObjectSetInternalValuesPtr = GetStaticMethodPointer(TEXT("ScriptingObjectCreate"));
|
||||
return CallStaticMethod<MObject*, void*, void*, const Guid*>(ScriptingObjectSetInternalValuesPtr, klass->_handle, unmanagedPtr, id);
|
||||
#else
|
||||
MObject* object = MCore::Object::New(klass);
|
||||
if (object)
|
||||
{
|
||||
MCore::ScriptingObject::SetInternalValues(klass, object, unmanagedPtr, id);
|
||||
MCore::Object::Init(object);
|
||||
}
|
||||
return object;
|
||||
#endif
|
||||
}
|
||||
|
||||
const MAssembly::ClassesDictionary& MAssembly::GetClasses() const
|
||||
@@ -1241,8 +1272,8 @@ void MField::GetValue(MObject* instance, void* result) const
|
||||
|
||||
void MField::GetValueReference(MObject* instance, void* result) const
|
||||
{
|
||||
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReferenceWithOffset"));
|
||||
CallStaticMethod<void, void*, int, void*>(FieldGetValueReferencePtr, instance, _fieldOffset, result);
|
||||
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference"));
|
||||
CallStaticMethod<void, void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
|
||||
}
|
||||
|
||||
MObject* MField::GetValueBoxed(MObject* instance) const
|
||||
@@ -1767,11 +1798,6 @@ void* GetStaticMethodPointer(const String& methodName)
|
||||
|
||||
#elif DOTNET_HOST_MONO
|
||||
|
||||
#ifdef USE_MONO_AOT_MODULE
|
||||
void* MonoAotModuleHandle = nullptr;
|
||||
#endif
|
||||
MonoDomain* MonoDomainHandle = nullptr;
|
||||
|
||||
void OnLogCallback(const char* logDomain, const char* logLevel, const char* message, mono_bool fatal, void* userData)
|
||||
{
|
||||
String currentDomain(logDomain);
|
||||
|
||||
@@ -2157,7 +2157,7 @@ MObject* MCore::ScriptingObject::CreateScriptingObject(MClass* klass, void* unma
|
||||
if (managedInstance)
|
||||
{
|
||||
// Set unmanaged object handle and id
|
||||
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, unmanagedPtr, _id);
|
||||
MCore::ScriptingObject::SetInternalValues(klass, managedInstance, unmanagedPtr, id);
|
||||
|
||||
// Initialize managed instance (calls constructor)
|
||||
MCore::Object::Init(managedInstance);
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "Engine/Scripting/Types.h"
|
||||
|
||||
#if !USE_CSHARP
|
||||
|
||||
#include "Engine/Core/Types/Span.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MCore.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MDomain.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
|
||||
@@ -493,9 +493,11 @@ bool Scripting::Load()
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float3"];
|
||||
flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Float4"];
|
||||
#endif
|
||||
#if USE_CSHARP
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector2")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector2"];
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector3")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector3"];
|
||||
flaxEngineModule->ClassToTypeIndex[flaxEngineModule->Assembly->GetClass("FlaxEngine.Vector4")] = flaxEngineModule->TypeNameToTypeIndex["FlaxEngine.Vector4"];
|
||||
#endif
|
||||
|
||||
#if USE_EDITOR
|
||||
// Skip loading game modules in Editor on startup - Editor loads them later during splash screen (eg. after first compilation)
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "BinaryModule.h"
|
||||
#include "Engine/Level/Actor.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Pair.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Content/Asset.h"
|
||||
#include "Engine/Content/Content.h"
|
||||
@@ -25,7 +26,8 @@
|
||||
#define ScriptingObject_id "__internalId"
|
||||
|
||||
// TODO: don't leak memory (use some kind of late manual GC for those wrapper objects)
|
||||
Dictionary<ScriptingObject*, void*> ScriptingObjectsInterfaceWrappers;
|
||||
typedef Pair<ScriptingObject*, ScriptingTypeHandle> ScriptingObjectsInterfaceKey;
|
||||
Dictionary<ScriptingObjectsInterfaceKey, void*> ScriptingObjectsInterfaceWrappers;
|
||||
|
||||
SerializableScriptingObject::SerializableScriptingObject(const SpawnParams& params)
|
||||
: ScriptingObject(params)
|
||||
@@ -202,10 +204,10 @@ ScriptingObject* ScriptingObject::FromInterface(void* interfaceObj, const Script
|
||||
}
|
||||
|
||||
// Special case for interface wrapper object
|
||||
for (auto& e : ScriptingObjectsInterfaceWrappers)
|
||||
for (const auto& e : ScriptingObjectsInterfaceWrappers)
|
||||
{
|
||||
if (e.Value == interfaceObj)
|
||||
return e.Key;
|
||||
return e.Key.First;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -226,10 +228,11 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
|
||||
else if (interface)
|
||||
{
|
||||
// Interface implemented in scripting (eg. C# class inherits C++ interface)
|
||||
if (!ScriptingObjectsInterfaceWrappers.TryGet(obj, result))
|
||||
const ScriptingObjectsInterfaceKey key(obj, interfaceType);
|
||||
if (!ScriptingObjectsInterfaceWrappers.TryGet(key, result))
|
||||
{
|
||||
result = interfaceType.GetType().Interface.GetInterfaceWrapper(obj);
|
||||
ScriptingObjectsInterfaceWrappers.Add(obj, result);
|
||||
ScriptingObjectsInterfaceWrappers.Add(key, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@@ -241,7 +244,7 @@ ScriptingObject* ScriptingObject::ToNative(MObject* obj)
|
||||
#if USE_CSHARP
|
||||
if (obj)
|
||||
{
|
||||
#if USE_MONO
|
||||
#if USE_MONO || USE_MONO_AOT
|
||||
const auto ptrField = MCore::Object::GetClass(obj)->GetField(ScriptingObject_unmanagedPtr);
|
||||
CHECK_RETURN(ptrField, nullptr);
|
||||
ptrField->GetValue(obj, &ptr);
|
||||
|
||||
@@ -113,7 +113,7 @@ void SpriteRender::Draw(RenderContext& renderContext)
|
||||
auto model = _quadModel.As<Model>();
|
||||
if (model->GetLoadedLODs() == 0)
|
||||
return;
|
||||
const auto& view = renderContext.View;
|
||||
const auto& view = (renderContext.LodProxyView ? *renderContext.LodProxyView : renderContext.View);
|
||||
Matrix m1, m2, m3, world;
|
||||
Matrix::Scaling(_size.X, _size.Y, 1.0f, m2);
|
||||
Matrix::RotationY(PI, m3);
|
||||
|
||||
@@ -56,6 +56,7 @@ UICanvas::UICanvas(const SpawnParams& params)
|
||||
UICanvas_EndPlay = mclass->GetMethod("EndPlay");
|
||||
UICanvas_ParentChanged = mclass->GetMethod("ParentChanged");
|
||||
UICanvas_Serialize = mclass->GetMethod("Serialize");
|
||||
Platform::MemoryBarrier();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user