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

This commit is contained in:
Menotdan
2023-10-12 13:13:53 -04:00
66 changed files with 593 additions and 287 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -182,6 +182,7 @@ namespace FlaxEditor.GUI.Input
}
SlidingEnd?.Invoke();
Defocus();
Parent?.Focus();
}
/// <inheritdoc />

View File

@@ -241,7 +241,7 @@ namespace FlaxEditor.GUI
{
DoubleClick?.Invoke();
RowDoubleClick?.Invoke(this);
return base.OnMouseDoubleClick(location, button);
}

View File

@@ -104,7 +104,7 @@ namespace FlaxEditor.Modules
hint = "Too long name.";
return false;
}
if (item.IsFolder && shortName.EndsWith("."))
{
hint = "Name cannot end with '.'";

View File

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

View File

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

View File

@@ -332,7 +332,7 @@ namespace FlaxEditor.Modules
continue;
scenes.Add(s);
}
// In play-mode Editor mocks the level streaming script
if (Editor.IsPlayMode)
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -190,7 +190,6 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject*
DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects()
{
ASSERT(IsInMainThread());
ObjectsRemovalService::Flush();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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