Compare commits
119 Commits
b23606c5eb
...
sdl_platfo
| Author | SHA1 | Date | |
|---|---|---|---|
| 43c4d45080 | |||
| 56a85f6ac0 | |||
| 1b8e25cb86 | |||
| 7088ce8742 | |||
| c7326ea483 | |||
| 523cad3b2c | |||
| ff6816396c | |||
| 24b8ad77fe | |||
| 3008d8037d | |||
| 0973363c64 | |||
| 5d45b9ea1c | |||
| c40f7c12f2 | |||
| 1b2d6372b2 | |||
| 0782ea889c | |||
| ef89501111 | |||
| 608353b996 | |||
| 221325ef09 | |||
| 8f57c91a9e | |||
| 968de34cae | |||
| 6586a98f8d | |||
| b3510b0e44 | |||
| d5a92c1942 | |||
| 417f82826f | |||
| 63bed0986a | |||
| c40eefc79d | |||
| d68631dd20 | |||
| e77b772010 | |||
| e41e956386 | |||
| 33e47c646b | |||
| b30ce6b84f | |||
| 02f67b25f3 | |||
| 469a422681 | |||
| 42fa0ffdd1 | |||
| f97ee72f1c | |||
| 89c93dd4f7 | |||
| 60cd8f702e | |||
| f376ec5c8a | |||
| 82bb297119 | |||
| ed994cb560 | |||
| 8efe2134f0 | |||
| 8efc4715c6 | |||
| 48c60144ae | |||
| 249cde467e | |||
| e2eadc87b6 | |||
| bc4b94d2bc | |||
| ecf074801f | |||
| 74bac97f44 | |||
| d7eebb699c | |||
| dde07bac8d | |||
| 5c8e593d89 | |||
| 46fd5a5855 | |||
| 74c1e200ce | |||
| 31945a53a2 | |||
| 3e91ba3fb2 | |||
|
|
e257f9e4a0 | ||
|
|
056de752ed | ||
|
|
76700c0b24 | ||
|
|
9fdcff657d | ||
|
|
2b6339c05c | ||
|
|
bb91202439 | ||
|
|
f25e9f262a | ||
|
|
ee51077f49 | ||
|
|
950e958a58 | ||
|
|
5fdbed2b56 | ||
|
|
0e627577fc | ||
|
|
4846d4b024 | ||
|
|
5e5293bf7b | ||
|
|
d88477dcae | ||
|
|
bd58bd91b4 | ||
|
|
7ce0d88bdc | ||
|
|
98bb2d40d6 | ||
|
|
f4bc620bbd | ||
|
|
0313bf32c9 | ||
|
|
0c887cd29e | ||
|
|
5bd9bce634 | ||
|
|
2a53d0a462 | ||
| 82bd915274 | |||
|
|
71391cf1cc | ||
|
|
b5286af526 | ||
|
|
9f07a2a54e | ||
|
|
c39c642b60 | ||
|
|
02cff3973a | ||
|
|
a63b97d31d | ||
|
|
ca52122656 | ||
|
|
20a7fcf6a0 | ||
|
|
43665aa7eb | ||
|
|
3b9b49950c | ||
|
|
0a8752ec0a | ||
|
|
47685dc2be | ||
|
|
517ee5bb25 | ||
|
|
3ab01d3576 | ||
|
|
31b6d4d658 | ||
|
|
08f840d642 | ||
|
|
776b6259cd | ||
|
|
5c81c71116 | ||
|
|
188b635ea0 | ||
|
|
56066a3212 | ||
|
|
ed50ce9c90 | ||
|
|
a7e77f6e21 | ||
|
|
56278b17ee | ||
|
|
bd78db72b9 | ||
|
|
32bd72fecd | ||
|
|
3a798a70fa | ||
|
|
02429266b1 | ||
|
|
77aea0c69c | ||
|
|
6a3ce862cb | ||
|
|
93217da619 | ||
|
|
63def54dad | ||
|
|
00f9a28729 | ||
|
|
56beca0db4 | ||
|
|
64cd898a65 | ||
|
|
90472a4b31 | ||
|
|
0007185b5f | ||
|
|
1bf6612002 | ||
|
|
d9a18b1d31 | ||
|
|
465f30661f | ||
|
|
a62ca5452e | ||
|
|
2d56411e5f | ||
|
|
f8dc8ab903 |
@@ -4,7 +4,7 @@
|
|||||||
"Major": 1,
|
"Major": 1,
|
||||||
"Minor": 11,
|
"Minor": 11,
|
||||||
"Revision": 0,
|
"Revision": 0,
|
||||||
"Build": 6804
|
"Build": 6805
|
||||||
},
|
},
|
||||||
"Company": "Flax",
|
"Company": "Flax",
|
||||||
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
"Copyright": "Copyright (c) 2012-2025 Wojciech Figat. All rights reserved.",
|
||||||
|
|||||||
@@ -281,6 +281,13 @@ namespace FlaxEditor.Content
|
|||||||
|
|
||||||
private void CacheData()
|
private void CacheData()
|
||||||
{
|
{
|
||||||
|
if (!_asset)
|
||||||
|
{
|
||||||
|
_parameters = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||||
|
_methods = Utils.GetEmptyArray<ScriptMemberInfo>();
|
||||||
|
_attributes = Utils.GetEmptyArray<Attribute>();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (_parameters != null)
|
if (_parameters != null)
|
||||||
return;
|
return;
|
||||||
if (_asset.WaitForLoaded())
|
if (_asset.WaitForLoaded())
|
||||||
@@ -344,13 +351,13 @@ namespace FlaxEditor.Content
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name => Path.GetFileNameWithoutExtension(_asset.Path);
|
public string Name => _asset ? Path.GetFileNameWithoutExtension(_asset.Path) : null;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Namespace => string.Empty;
|
public string Namespace => string.Empty;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string TypeName => JsonSerializer.GetStringID(_asset.ID);
|
public string TypeName => _asset ? JsonSerializer.GetStringID(_asset.ID) : null;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public bool IsPublic => true;
|
public bool IsPublic => true;
|
||||||
|
|||||||
@@ -1368,7 +1368,10 @@ bool CookAssetsStep::Perform(CookingData& data)
|
|||||||
{
|
{
|
||||||
typeName = e.TypeName;
|
typeName = e.TypeName;
|
||||||
}
|
}
|
||||||
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
if (e.Count == 1)
|
||||||
|
LOG(Info, "{0}: 1 asset of total size {1}", typeName, Utilities::BytesToText(e.ContentSize));
|
||||||
|
else
|
||||||
|
LOG(Info, "{0}: {1:>4} assets of total size {2}", typeName, e.Count, Utilities::BytesToText(e.ContentSize));
|
||||||
}
|
}
|
||||||
LOG(Info, "");
|
LOG(Info, "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ namespace FlaxEditor.CustomEditors
|
|||||||
return new GenericEditor();
|
return new GenericEditor();
|
||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "CustomEditorsUtilInternal_GetCustomEditor", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
|
[return: MarshalUsing(typeof(SystemTypeMarshaller))]
|
||||||
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
|
internal static partial Type Internal_GetCustomEditor([MarshalUsing(typeof(SystemTypeMarshaller))] Type targetType);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -526,6 +526,23 @@ int32 Editor::LoadProduct()
|
|||||||
return 12;
|
return 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the last opened project path
|
||||||
|
String localCachePath;
|
||||||
|
FileSystem::GetSpecialFolderPath(SpecialFolder::AppData, localCachePath);
|
||||||
|
String editorConfigPath = localCachePath / TEXT("Flax");
|
||||||
|
String lastProjectSettingPath = editorConfigPath / TEXT("LastProject.txt");
|
||||||
|
if (!FileSystem::DirectoryExists(editorConfigPath))
|
||||||
|
FileSystem::CreateDirectory(editorConfigPath);
|
||||||
|
String lastProjectPath;
|
||||||
|
if (FileSystem::FileExists(lastProjectSettingPath))
|
||||||
|
File::ReadAllText(lastProjectSettingPath, lastProjectPath);
|
||||||
|
if (!FileSystem::DirectoryExists(lastProjectPath))
|
||||||
|
lastProjectPath = String::Empty;
|
||||||
|
|
||||||
|
// Try to open the last project when requested
|
||||||
|
if (projectPath.IsEmpty() && CommandLine::Options.LastProject.IsTrue() && !lastProjectPath.IsEmpty())
|
||||||
|
projectPath = lastProjectPath;
|
||||||
|
|
||||||
// Missing project case
|
// Missing project case
|
||||||
if (projectPath.IsEmpty())
|
if (projectPath.IsEmpty())
|
||||||
{
|
{
|
||||||
@@ -541,7 +558,7 @@ int32 Editor::LoadProduct()
|
|||||||
Array<String> files;
|
Array<String> files;
|
||||||
if (FileSystem::ShowOpenFileDialog(
|
if (FileSystem::ShowOpenFileDialog(
|
||||||
nullptr,
|
nullptr,
|
||||||
StringView::Empty,
|
lastProjectPath,
|
||||||
TEXT("Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0"),
|
TEXT("Project files (*.flaxproj)\0*.flaxproj\0All files (*.*)\0*.*\0"),
|
||||||
false,
|
false,
|
||||||
TEXT("Select project to open in Editor"),
|
TEXT("Select project to open in Editor"),
|
||||||
@@ -625,6 +642,10 @@ int32 Editor::LoadProduct()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the last opened project path
|
||||||
|
if (lastProjectPath.Compare(Project->ProjectFolderPath) != 0)
|
||||||
|
File::WriteAllText(lastProjectSettingPath, Project->ProjectFolderPath, Encoding::UTF8);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,18 +69,18 @@ namespace FlaxEditor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
|
/// Gets a value indicating whether this Editor is running a dev instance of the engine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsDevInstance", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsDevInstance")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool IsDevInstance();
|
internal static partial bool IsDevInstance();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
|
/// Gets a value indicating whether this Editor is running as official build (distributed via Flax services).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsOfficialBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsOfficialBuild")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool IsOfficialBuild();
|
internal static partial bool IsOfficialBuild();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_IsPlayMode")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_IsPlayMode();
|
internal static partial bool Internal_IsPlayMode();
|
||||||
|
|
||||||
@@ -1647,96 +1647,103 @@ namespace FlaxEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_ReadOutputLogs", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref byte[] outLogTypes, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "outCapacity")] ref long[] outLogTimes, int outCapacity);
|
internal static partial int Internal_ReadOutputLogs([MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<string, FlaxEngine.Interop.NativeString>), CountElementName = "outCapacity")] ref string[] outMessages, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 3)] ref byte[] outLogTypes, [MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I8, SizeParamIndex = 3)] ref long[] outLogTimes, int outCapacity);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetPlayMode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetPlayMode")]
|
||||||
internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
|
internal static partial void Internal_SetPlayMode([MarshalAs(UnmanagedType.U1)] bool value);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
internal static string Internal_GetProjectPath()
|
||||||
internal static partial string Internal_GetProjectPath();
|
{
|
||||||
|
Internal_GetProjectPath(out string projectPath);
|
||||||
|
return projectPath;
|
||||||
|
}
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetProjectPath", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
|
internal static partial void Internal_GetProjectPath([MarshalUsing(typeof(FlaxEngine.Interop.StringViewMarshaller))] out string projectPath);
|
||||||
|
|
||||||
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloneAssetFile", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
internal static partial bool Internal_CloneAssetFile(string dstPath, string srcPath, ref Guid dstId);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAudioClipMetadata", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAudioClipMetadata")]
|
||||||
internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
internal static partial void Internal_GetAudioClipMetadata(IntPtr obj, out int originalSize, out int importedSize);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SaveJsonAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
internal static partial bool Internal_SaveJsonAsset(string outputPath, string data, string typename);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CopyCache", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CopyCache")]
|
||||||
internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
internal static partial void Internal_CopyCache(ref Guid dstId, ref Guid srcId);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_BakeLightmaps", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_BakeLightmaps")]
|
||||||
internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
|
internal static partial void Internal_BakeLightmaps([MarshalAs(UnmanagedType.U1)] bool cancel);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetShaderAssetSourceCode", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
|
[return: MarshalUsing(typeof(FlaxEngine.Interop.StringViewMarshaller))]
|
||||||
internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
internal static partial string Internal_GetShaderAssetSourceCode(IntPtr obj);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CookMeshCollision", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
internal static partial bool Internal_CookMeshCollision(string path, CollisionDataType type, IntPtr model, int modelLodIndex, uint materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int convexVertexLimit);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetCollisionWires", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetCollisionWires")]
|
||||||
internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount);
|
internal static partial void Internal_GetCollisionWires(IntPtr collisionData, [MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = "trianglesCount")] out Float3[] triangles, [MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "indicesCount")] out int[] indices, out int trianglesCount, out int indicesCount);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetEditorBoxWithChildren", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetEditorBoxWithChildren")]
|
||||||
internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
internal static partial void Internal_GetEditorBoxWithChildren(IntPtr obj, out BoundingBox resultAsRef);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetOptions", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetOptions")]
|
||||||
internal static partial void Internal_SetOptions(ref InternalOptions options);
|
internal static partial void Internal_SetOptions(ref InternalOptions options);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DrawNavMesh", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DrawNavMesh")]
|
||||||
internal static partial void Internal_DrawNavMesh();
|
internal static partial void Internal_DrawNavMesh();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CloseSplashScreen")]
|
||||||
internal static partial void Internal_CloseSplashScreen();
|
internal static partial void Internal_CloseSplashScreen();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CreateVisualScript", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
internal static partial bool Internal_CreateVisualScript(string outputPath, string baseTypename);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanImport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
internal static partial string Internal_CanImport(string extension);
|
internal static partial string Internal_CanImport(string extension);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanExport", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CanExport(string path);
|
internal static partial bool Internal_CanExport(string path);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_Export", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_Export(string inputPath, string outputFolder);
|
internal static partial bool Internal_Export(string inputPath, string outputFolder);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsEveryAssemblyLoaded", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsEveryAssemblyLoaded")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
|
internal static partial bool Internal_GetIsEveryAssemblyLoaded();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetLastProjectOpenedEngineBuild", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetLastProjectOpenedEngineBuild")]
|
||||||
internal static partial int Internal_GetLastProjectOpenedEngineBuild();
|
internal static partial int Internal_GetLastProjectOpenedEngineBuild();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsCSGActive", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetIsCSGActive")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_GetIsCSGActive();
|
internal static partial bool Internal_GetIsCSGActive();
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_RunVisualScriptBreakpointLoopTick")]
|
||||||
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
internal static partial void Internal_RunVisualScriptBreakpointLoopTick(float deltaTime);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_DeserializeSceneObject", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
internal static partial void Internal_DeserializeSceneObject(IntPtr sceneObject, string json);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_LoadAsset", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_LoadAsset")]
|
||||||
internal static partial void Internal_LoadAsset(ref Guid id);
|
internal static partial void Internal_LoadAsset(ref Guid id);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanSetToRoot", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_CanSetToRoot")]
|
||||||
[return: MarshalAs(UnmanagedType.U1)]
|
[return: MarshalAs(UnmanagedType.U1)]
|
||||||
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
internal static partial bool Internal_CanSetToRoot(IntPtr prefab, IntPtr newRoot);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_GetAnimationTime")]
|
||||||
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
internal static partial float Internal_GetAnimationTime(IntPtr animatedModel);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetAnimationTime", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "EditorInternal_SetAnimationTime")]
|
||||||
internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
internal static partial void Internal_SetAnimationTime(IntPtr animatedModel, float time);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -58,22 +58,22 @@ void OnLogMessage(LogType type, const StringView& msg)
|
|||||||
{
|
{
|
||||||
ScopeLock lock(CachedLogDataLocker);
|
ScopeLock lock(CachedLogDataLocker);
|
||||||
|
|
||||||
CachedLogData.EnsureCapacity(4 + 8 + 4 + msg.Length() * 2);
|
CachedLogData.EnsureCapacity(sizeof(int32) + sizeof(DateTime) + sizeof(int32) + msg.Length() * sizeof(Char));
|
||||||
|
|
||||||
// Log Type
|
// Log Type
|
||||||
int32 buf = (int32)type;
|
int32 buf = (int32)type;
|
||||||
CachedLogData.Add((byte*)&buf, 4);
|
CachedLogData.Add((byte*)&buf, sizeof(int32));
|
||||||
|
|
||||||
// Time
|
// Time
|
||||||
auto time = DateTime::Now();
|
auto time = DateTime::Now();
|
||||||
CachedLogData.Add((byte*)&time.Ticks, 8);
|
CachedLogData.Add((byte*)&time.Ticks, sizeof(DateTime));
|
||||||
|
|
||||||
// Message Length
|
// Message Length
|
||||||
buf = msg.Length();
|
buf = msg.Length();
|
||||||
CachedLogData.Add((byte*)&buf, 4);
|
CachedLogData.Add((byte*)&buf, sizeof(int32));
|
||||||
|
|
||||||
// Message
|
// Message
|
||||||
CachedLogData.Add((byte*)msg.Get(), msg.Length() * 2);
|
CachedLogData.Add((byte*)msg.Get(), msg.Length() * sizeof(Char));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_IsDevInstance()
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_IsDevInstance()
|
||||||
@@ -99,7 +99,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_IsPlayMode()
|
|||||||
return Editor::IsPlayMode;
|
return Editor::IsPlayMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages, MArray** outLogTypes, MArray** outLogTimes, int outArraySize)
|
DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(NativeArray<String>* outMessages, NativeArray<byte>* outLogTypes, NativeArray<int64>* outLogTimes, int outArraySize)
|
||||||
{
|
{
|
||||||
ScopeLock lock(CachedLogDataLocker);
|
ScopeLock lock(CachedLogDataLocker);
|
||||||
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
|
if (CachedLogData.IsEmpty() || CachedLogData.Get() == nullptr)
|
||||||
@@ -108,27 +108,30 @@ DEFINE_INTERNAL_CALL(int32) EditorInternal_ReadOutputLogs(MArray** outMessages,
|
|||||||
int32 count = 0;
|
int32 count = 0;
|
||||||
const int32 maxCount = outArraySize;
|
const int32 maxCount = outArraySize;
|
||||||
|
|
||||||
|
String* messages = &outMessages->data[0];
|
||||||
byte* ptr = CachedLogData.Get();
|
byte* ptr = CachedLogData.Get();
|
||||||
byte* end = ptr + CachedLogData.Count();
|
byte* end = ptr + CachedLogData.Count();
|
||||||
byte* outLogTypesPtr = MCore::Array::GetAddress<byte>(*outLogTypes);
|
byte* outLogTypesPtr = outLogTypes->data;
|
||||||
int64* outLogTimesPtr = MCore::Array::GetAddress<int64>(*outLogTimes);
|
int64* outLogTimesPtr = outLogTimes->data;
|
||||||
while (count < maxCount && ptr != end)
|
while (count < maxCount && ptr != end)
|
||||||
{
|
{
|
||||||
auto type = (byte)*(int32*)ptr;
|
auto type = (byte)*(int32*)ptr;
|
||||||
ptr += 4;
|
ptr += sizeof(int32);
|
||||||
|
|
||||||
auto time = *(int64*)ptr;
|
auto time = *(int64*)ptr;
|
||||||
ptr += 8;
|
ptr += sizeof(int64);
|
||||||
|
|
||||||
auto length = *(int32*)ptr;
|
auto length = *(int32*)ptr;
|
||||||
ptr += 4;
|
ptr += sizeof(int32);
|
||||||
|
|
||||||
auto msg = (Char*)ptr;
|
auto msg = (Char*)ptr;
|
||||||
ptr += length * 2;
|
ptr += length * sizeof(Char);
|
||||||
|
|
||||||
auto msgObj = MUtils::ToString(StringView(msg, length));
|
auto msgObj = String(msg, length);
|
||||||
|
|
||||||
MCore::GC::WriteArrayRef(*outMessages, (MObject*)msgObj, count);
|
String& str = messages[count];
|
||||||
|
ASSERT(str.Get() == nullptr && str.Length() == 0);
|
||||||
|
str = msgObj;
|
||||||
outLogTypesPtr[count] = type;
|
outLogTypesPtr[count] = type;
|
||||||
outLogTimesPtr[count] = time;
|
outLogTimesPtr[count] = time;
|
||||||
|
|
||||||
@@ -147,9 +150,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_SetPlayMode(bool value)
|
|||||||
Editor::IsPlayMode = value;
|
Editor::IsPlayMode = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetProjectPath()
|
DEFINE_INTERNAL_CALL(void) EditorInternal_GetProjectPath(StringView* projectPath)
|
||||||
{
|
{
|
||||||
return MUtils::ToString(Editor::Project->ProjectPath);
|
*projectPath = Editor::Project->ProjectPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
|
DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
|
||||||
@@ -159,6 +162,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_CloseSplashScreen()
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MString* srcPathObj, Guid* dstId)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MString* srcPathObj, Guid* dstId)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
// Get normalized paths
|
// Get normalized paths
|
||||||
String dstPath, srcPath;
|
String dstPath, srcPath;
|
||||||
MUtils::ToString(dstPathObj, dstPath);
|
MUtils::ToString(dstPathObj, dstPath);
|
||||||
@@ -172,6 +176,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CloneAssetFile(MString* dstPathObj, MS
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPathObj, MString* baseTypenameObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
String outputPath;
|
String outputPath;
|
||||||
MUtils::ToString(outputPathObj, outputPath);
|
MUtils::ToString(outputPathObj, outputPath);
|
||||||
FileSystem::NormalizePath(outputPath);
|
FileSystem::NormalizePath(outputPath);
|
||||||
@@ -182,6 +187,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CreateVisualScript(MString* outputPath
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(MString*) EditorInternal_CanImport(MString* extensionObj)
|
DEFINE_INTERNAL_CALL(MString*) EditorInternal_CanImport(MString* extensionObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
String extension;
|
String extension;
|
||||||
MUtils::ToString(extensionObj, extension);
|
MUtils::ToString(extensionObj, extension);
|
||||||
if (extension.Length() > 0 && extension[0] == '.')
|
if (extension.Length() > 0 && extension[0] == '.')
|
||||||
@@ -199,6 +205,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetAudioClipMetadata(AudioClip* clip,
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj, MString* dataObj, MString* dataTypeNameObj)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj, MString* dataObj, MString* dataTypeNameObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
String outputPath;
|
String outputPath;
|
||||||
MUtils::ToString(outputPathObj, outputPath);
|
MUtils::ToString(outputPathObj, outputPath);
|
||||||
FileSystem::NormalizePath(outputPath);
|
FileSystem::NormalizePath(outputPath);
|
||||||
@@ -216,6 +223,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_SaveJsonAsset(MString* outputPathObj,
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
#if COMPILE_WITH_ASSETS_EXPORTER
|
#if COMPILE_WITH_ASSETS_EXPORTER
|
||||||
String path;
|
String path;
|
||||||
MUtils::ToString(pathObj, path);
|
MUtils::ToString(pathObj, path);
|
||||||
@@ -229,6 +237,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CanExport(MString* pathObj)
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString* outputFolderObj)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString* outputFolderObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
#if COMPILE_WITH_ASSETS_EXPORTER
|
#if COMPILE_WITH_ASSETS_EXPORTER
|
||||||
String inputPath;
|
String inputPath;
|
||||||
MUtils::ToString(inputPathObj, inputPath);
|
MUtils::ToString(inputPathObj, inputPath);
|
||||||
@@ -246,6 +255,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_Export(MString* inputPathObj, MString*
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_CopyCache(Guid* dstId, Guid* srcId)
|
DEFINE_INTERNAL_CALL(void) EditorInternal_CopyCache(Guid* dstId, Guid* srcId)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
ShaderCacheManager::CopyCache(*dstId, *srcId);
|
ShaderCacheManager::CopyCache(*dstId, *srcId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,6 +270,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_BakeLightmaps(bool cancel)
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAsset* obj)
|
DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAsset* obj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
|
INTERNAL_CALL_CHECK_RETURN(obj, nullptr);
|
||||||
if (obj->WaitForLoaded())
|
if (obj->WaitForLoaded())
|
||||||
DebugLog::ThrowNullReference();
|
DebugLog::ThrowNullReference();
|
||||||
@@ -287,6 +298,7 @@ DEFINE_INTERNAL_CALL(MString*) EditorInternal_GetShaderAssetSourceCode(BinaryAss
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
|
DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, CollisionDataType type, ModelBase* modelObj, int32 modelLodIndex, uint32 materialSlotsMask, ConvexMeshGenerationFlags convexFlags, int32 convexVertexLimit)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
#if COMPILE_WITH_PHYSICS_COOKING
|
#if COMPILE_WITH_PHYSICS_COOKING
|
||||||
CollisionCooking::Argument arg;
|
CollisionCooking::Argument arg;
|
||||||
String path;
|
String path;
|
||||||
@@ -307,6 +319,7 @@ DEFINE_INTERNAL_CALL(bool) EditorInternal_CookMeshCollision(MString* pathObj, Co
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* collisionData, MArray** triangles, MArray** indices, int* trianglesCount, int* indicesCount)
|
DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* collisionData, MArray** triangles, MArray** indices, int* trianglesCount, int* indicesCount)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
|
if (!collisionData || collisionData->WaitForLoaded() || collisionData->GetOptions().Type == CollisionDataType::None)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -332,6 +345,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_GetCollisionWires(CollisionData* colli
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
|
DEFINE_INTERNAL_CALL(void) EditorInternal_GetEditorBoxWithChildren(Actor* obj, BoundingBox* result)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
INTERNAL_CALL_CHECK(obj);
|
INTERNAL_CALL_CHECK(obj);
|
||||||
*result = obj->GetEditorBoxChildren();
|
*result = obj->GetEditorBoxChildren();
|
||||||
}
|
}
|
||||||
@@ -461,6 +475,7 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
|
DEFINE_INTERNAL_CALL(void) EditorInternal_DeserializeSceneObject(SceneObject* sceneObject, MString* jsonObj)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
PROFILE_CPU_NAMED("DeserializeSceneObject");
|
PROFILE_CPU_NAMED("DeserializeSceneObject");
|
||||||
|
|
||||||
StringAnsi json;
|
StringAnsi json;
|
||||||
@@ -531,10 +546,9 @@ DEFINE_INTERNAL_CALL(MTypeObject*) CustomEditorsUtilInternal_GetCustomEditor(MTy
|
|||||||
return CustomEditorsUtil::GetCustomEditor(targetType);
|
return CustomEditorsUtil::GetCustomEditor(targetType);
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(MArray*) LayersAndTagsSettingsInternal_GetCurrentLayers(int* layersCount)
|
DEFINE_INTERNAL_CALL(NativeSpan<String>) LayersAndTagsSettingsInternal_GetCurrentLayers()
|
||||||
{
|
{
|
||||||
*layersCount = Math::Max(1, Level::GetNonEmptyLayerNamesCount());
|
return NativeSpan<String>::AsSpan(Level::Layers, Math::Max(1, Level::GetNonEmptyLayerNamesCount()));
|
||||||
return MUtils::ToArray(Span<String>(Level::Layers, *layersCount));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_INTERNAL_CALL(void) GameSettingsInternal_Apply()
|
DEFINE_INTERNAL_CALL(void) GameSettingsInternal_Apply()
|
||||||
|
|||||||
@@ -397,7 +397,8 @@ bool ManagedEditor::HasGameViewportFocus() const
|
|||||||
Internal_HasGameViewportFocus = GetClass()->GetMethod("Internal_HasGameViewportFocus");
|
Internal_HasGameViewportFocus = GetClass()->GetMethod("Internal_HasGameViewportFocus");
|
||||||
ASSERT(Internal_HasGameViewportFocus);
|
ASSERT(Internal_HasGameViewportFocus);
|
||||||
}
|
}
|
||||||
result = MUtils::Unbox<bool>(Internal_HasGameViewportFocus->Invoke(GetManagedInstance(), nullptr, nullptr), true);
|
auto invk = Internal_HasGameViewportFocus->Invoke(GetManagedInstance(), nullptr, nullptr);
|
||||||
|
result = MUtils::Unbox<bool>(invk, true);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,6 +334,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (editor == null)
|
||||||
|
editor = Editor.Instance.CodeEditing.Editors[0];
|
||||||
|
|
||||||
Editor.Instance.CodeEditing.SelectedEditor = editor;
|
Editor.Instance.CodeEditing.SelectedEditor = editor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
var vsCode = codeEditing.GetInBuildEditor(CodeEditorTypes.VSCode);
|
var vsCode = codeEditing.GetInBuildEditor(CodeEditorTypes.VSCode);
|
||||||
var rider = codeEditing.GetInBuildEditor(CodeEditorTypes.Rider);
|
var rider = codeEditing.GetInBuildEditor(CodeEditorTypes.Rider);
|
||||||
|
|
||||||
#if PLATFORM_WINDOW
|
#if PLATFORM_WINDOWS
|
||||||
// Favor the newest Visual Studio
|
// Favor the newest Visual Studio
|
||||||
for (int i = (int)CodeEditorTypes.VS2019; i >= (int)CodeEditorTypes.VS2008; i--)
|
for (int i = (int)CodeEditorTypes.VS2026; i >= (int)CodeEditorTypes.VS2008; i--)
|
||||||
{
|
{
|
||||||
var visualStudio = codeEditing.GetInBuildEditor((CodeEditorTypes)i);
|
var visualStudio = codeEditing.GetInBuildEditor((CodeEditorTypes)i);
|
||||||
if (visualStudio != null)
|
if (visualStudio != null)
|
||||||
@@ -74,7 +74,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
public string Name => "Default";
|
public string Name => "Default";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GenerateProjectCustomArgs => null;
|
public string GenerateProjectCustomArgs => _currentEditor?.GenerateProjectCustomArgs;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OpenSolution()
|
public void OpenSolution()
|
||||||
|
|||||||
@@ -22,71 +22,14 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
|||||||
public InBuildSourceCodeEditor(CodeEditorTypes type)
|
public InBuildSourceCodeEditor(CodeEditorTypes type)
|
||||||
{
|
{
|
||||||
Type = type;
|
Type = type;
|
||||||
switch (type)
|
Name = CodeEditingManager.GetName(type);
|
||||||
{
|
|
||||||
case CodeEditorTypes.Custom:
|
|
||||||
Name = "Custom";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.SystemDefault:
|
|
||||||
Name = "System Default";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2008:
|
|
||||||
Name = "Visual Studio 2008";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2010:
|
|
||||||
Name = "Visual Studio 2010";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2012:
|
|
||||||
Name = "Visual Studio 2012";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2013:
|
|
||||||
Name = "Visual Studio 2013";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2015:
|
|
||||||
Name = "Visual Studio 2015";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2017:
|
|
||||||
Name = "Visual Studio 2017";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2019:
|
|
||||||
Name = "Visual Studio 2019";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2022:
|
|
||||||
Name = "Visual Studio 2022";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VS2026:
|
|
||||||
Name = "Visual Studio 2026";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VSCode:
|
|
||||||
Name = "Visual Studio Code";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.VSCodeInsiders:
|
|
||||||
Name = "Visual Studio Code - Insiders";
|
|
||||||
break;
|
|
||||||
case CodeEditorTypes.Rider:
|
|
||||||
Name = "Rider";
|
|
||||||
break;
|
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GenerateProjectCustomArgs
|
public string GenerateProjectCustomArgs => CodeEditingManager.GetGenerateProjectCustomArgs(Type);
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
switch (Type)
|
|
||||||
{
|
|
||||||
case CodeEditorTypes.VSCodeInsiders:
|
|
||||||
case CodeEditorTypes.VSCode: return "-vscode -vs2022";
|
|
||||||
case CodeEditorTypes.Rider: return "-vs2022";
|
|
||||||
default: return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void OpenSolution()
|
public void OpenSolution()
|
||||||
|
|||||||
@@ -897,9 +897,11 @@ namespace FlaxEditor.Modules
|
|||||||
|
|
||||||
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
|
if (type.IsAssignableTo(typeof(AssetEditorWindow)))
|
||||||
{
|
{
|
||||||
var ctor = type.GetConstructor(new Type[] { typeof(Editor), typeof(AssetItem) });
|
|
||||||
var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
|
var assetItem = Editor.ContentDatabase.FindAsset(winData.AssetItemID);
|
||||||
|
var assetType = assetItem.GetType();
|
||||||
|
var ctor = type.GetConstructor(new Type[] { typeof(Editor), assetType });
|
||||||
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
|
var win = (AssetEditorWindow)ctor.Invoke(new object[] { Editor.Instance, assetItem });
|
||||||
|
|
||||||
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
win.Show(winData.DockState, winData.DockState != DockState.Float ? winData.DockedTo : null, winData.SelectOnShow, winData.SplitterValue);
|
||||||
if (winData.DockState == DockState.Float)
|
if (winData.DockState == DockState.Float)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -139,6 +139,34 @@ CodeEditor* CodeEditingManager::GetCodeEditor(CodeEditorTypes editorType)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String CodeEditingManager::GetName(CodeEditorTypes editorType)
|
||||||
|
{
|
||||||
|
const auto editor = GetCodeEditor(editorType);
|
||||||
|
if (editor)
|
||||||
|
{
|
||||||
|
return editor->GetName();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(Warning, "Missing code editor type {0}", (int32)editorType);
|
||||||
|
return String::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String CodeEditingManager::GetGenerateProjectCustomArgs(CodeEditorTypes editorType)
|
||||||
|
{
|
||||||
|
const auto editor = GetCodeEditor(editorType);
|
||||||
|
if (editor)
|
||||||
|
{
|
||||||
|
return editor->GetGenerateProjectCustomArgs();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOG(Warning, "Missing code editor type {0}", (int32)editorType);
|
||||||
|
return String::Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CodeEditingManager::OpenFile(CodeEditorTypes editorType, const String& path, int32 line)
|
void CodeEditingManager::OpenFile(CodeEditorTypes editorType, const String& path, int32 line)
|
||||||
{
|
{
|
||||||
const auto editor = GetCodeEditor(editorType);
|
const auto editor = GetCodeEditor(editorType);
|
||||||
|
|||||||
@@ -109,9 +109,18 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the name of the editor.
|
/// Gets the name of the editor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The name</returns>
|
/// <returns>The name.</returns>
|
||||||
virtual String GetName() const = 0;
|
virtual String GetName() const = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the custom arguments for the Flax.Build tool to add when generating project files for this code editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The custom arguments to generate project files.</returns>
|
||||||
|
virtual String GetGenerateProjectCustomArgs() const
|
||||||
|
{
|
||||||
|
return String::Empty;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the file.
|
/// Opens the file.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -169,6 +178,20 @@ public:
|
|||||||
/// <returns>The editor object or null if not found.</returns>
|
/// <returns>The editor object or null if not found.</returns>
|
||||||
static CodeEditor* GetCodeEditor(CodeEditorTypes editorType);
|
static CodeEditor* GetCodeEditor(CodeEditorTypes editorType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="editorType">The code editor type.</param>
|
||||||
|
/// <returns>The name.</returns>
|
||||||
|
API_FUNCTION() static String GetName(CodeEditorTypes editorType);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the custom arguments for the Flax.Build tool to add when generating project files for this code editor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="editorType">The code editor type.</param>
|
||||||
|
/// <returns>The custom arguments to generate project files.</returns>
|
||||||
|
API_FUNCTION() static String GetGenerateProjectCustomArgs(CodeEditorTypes editorType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Opens the file. Handles async opening.
|
/// Opens the file. Handles async opening.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -257,12 +257,17 @@ String RiderCodeEditor::GetName() const
|
|||||||
return TEXT("Rider");
|
return TEXT("Rider");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String RiderCodeEditor::GetGenerateProjectCustomArgs() const
|
||||||
|
{
|
||||||
|
return TEXT("-vs2022");
|
||||||
|
}
|
||||||
|
|
||||||
void RiderCodeEditor::OpenFile(const String& path, int32 line)
|
void RiderCodeEditor::OpenFile(const String& path, int32 line)
|
||||||
{
|
{
|
||||||
// Generate project files if solution is missing
|
// Generate project files if solution is missing
|
||||||
if (!FileSystem::FileExists(_solutionPath))
|
if (!FileSystem::FileExists(_solutionPath))
|
||||||
{
|
{
|
||||||
ScriptsBuilder::GenerateProject(TEXT("-vs2022"));
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
@@ -290,7 +295,7 @@ void RiderCodeEditor::OpenSolution()
|
|||||||
// Generate project files if solution is missing
|
// Generate project files if solution is missing
|
||||||
if (!FileSystem::FileExists(_solutionPath))
|
if (!FileSystem::FileExists(_solutionPath))
|
||||||
{
|
{
|
||||||
ScriptsBuilder::GenerateProject(TEXT("-vs2022"));
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open solution
|
// Open solution
|
||||||
@@ -312,5 +317,5 @@ void RiderCodeEditor::OpenSolution()
|
|||||||
|
|
||||||
void RiderCodeEditor::OnFileAdded(const String& path)
|
void RiderCodeEditor::OnFileAdded(const String& path)
|
||||||
{
|
{
|
||||||
ScriptsBuilder::GenerateProject();
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ public:
|
|||||||
// [CodeEditor]
|
// [CodeEditor]
|
||||||
CodeEditorTypes GetType() const override;
|
CodeEditorTypes GetType() const override;
|
||||||
String GetName() const override;
|
String GetName() const override;
|
||||||
|
String GetGenerateProjectCustomArgs() const override;
|
||||||
void OpenFile(const String& path, int32 line) override;
|
void OpenFile(const String& path, int32 line) override;
|
||||||
void OpenSolution() override;
|
void OpenSolution() override;
|
||||||
void OnFileAdded(const String& path) override;
|
void OnFileAdded(const String& path) override;
|
||||||
|
|||||||
@@ -148,12 +148,17 @@ String VisualStudioEditor::GetName() const
|
|||||||
return String(ToString(_version));
|
return String(ToString(_version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String VisualStudioEditor::GetGenerateProjectCustomArgs() const
|
||||||
|
{
|
||||||
|
return String::Format(TEXT("-{0}"), String(ToString(_version)).ToLower());
|
||||||
|
}
|
||||||
|
|
||||||
void VisualStudioEditor::OpenFile(const String& path, int32 line)
|
void VisualStudioEditor::OpenFile(const String& path, int32 line)
|
||||||
{
|
{
|
||||||
// Generate project files if solution is missing
|
// Generate project files if solution is missing
|
||||||
if (!FileSystem::FileExists(_solutionPath))
|
if (!FileSystem::FileExists(_solutionPath))
|
||||||
{
|
{
|
||||||
ScriptsBuilder::GenerateProject();
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open file
|
// Open file
|
||||||
@@ -172,7 +177,7 @@ void VisualStudioEditor::OpenSolution()
|
|||||||
// Generate project files if solution is missing
|
// Generate project files if solution is missing
|
||||||
if (!FileSystem::FileExists(_solutionPath))
|
if (!FileSystem::FileExists(_solutionPath))
|
||||||
{
|
{
|
||||||
ScriptsBuilder::GenerateProject();
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open solution
|
// Open solution
|
||||||
@@ -187,7 +192,7 @@ void VisualStudioEditor::OpenSolution()
|
|||||||
void VisualStudioEditor::OnFileAdded(const String& path)
|
void VisualStudioEditor::OnFileAdded(const String& path)
|
||||||
{
|
{
|
||||||
// TODO: finish dynamic files adding to the project - for now just regenerate it
|
// TODO: finish dynamic files adding to the project - for now just regenerate it
|
||||||
ScriptsBuilder::GenerateProject();
|
ScriptsBuilder::GenerateProject(GetGenerateProjectCustomArgs());
|
||||||
return;
|
return;
|
||||||
if (!FileSystem::FileExists(_solutionPath))
|
if (!FileSystem::FileExists(_solutionPath))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public:
|
|||||||
// [CodeEditor]
|
// [CodeEditor]
|
||||||
CodeEditorTypes GetType() const override;
|
CodeEditorTypes GetType() const override;
|
||||||
String GetName() const override;
|
String GetName() const override;
|
||||||
|
String GetGenerateProjectCustomArgs() const override;
|
||||||
void OpenFile(const String& path, int32 line) override;
|
void OpenFile(const String& path, int32 line) override;
|
||||||
void OpenSolution() override;
|
void OpenSolution() override;
|
||||||
void OnFileAdded(const String& path) override;
|
void OnFileAdded(const String& path) override;
|
||||||
|
|||||||
@@ -128,6 +128,11 @@ String VisualStudioCodeEditor::GetName() const
|
|||||||
return _isInsiders ? TEXT("Visual Studio Code - Insiders") : TEXT("Visual Studio Code");
|
return _isInsiders ? TEXT("Visual Studio Code - Insiders") : TEXT("Visual Studio Code");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String VisualStudioCodeEditor::GetGenerateProjectCustomArgs() const
|
||||||
|
{
|
||||||
|
return TEXT("-vs2022 -vscode");
|
||||||
|
}
|
||||||
|
|
||||||
void VisualStudioCodeEditor::OpenFile(const String& path, int32 line)
|
void VisualStudioCodeEditor::OpenFile(const String& path, int32 line)
|
||||||
{
|
{
|
||||||
// Generate VS solution files for intellisense
|
// Generate VS solution files for intellisense
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
// [CodeEditor]
|
// [CodeEditor]
|
||||||
CodeEditorTypes GetType() const override;
|
CodeEditorTypes GetType() const override;
|
||||||
String GetName() const override;
|
String GetName() const override;
|
||||||
|
String GetGenerateProjectCustomArgs() const override;
|
||||||
void OpenFile(const String& path, int32 line) override;
|
void OpenFile(const String& path, int32 line) override;
|
||||||
void OpenSolution() override;
|
void OpenSolution() override;
|
||||||
bool UseAsyncForOpen() const override;
|
bool UseAsyncForOpen() const override;
|
||||||
|
|||||||
@@ -406,6 +406,8 @@ namespace FlaxEngine.Utilities
|
|||||||
{
|
{
|
||||||
if (type == ScriptType.Null)
|
if (type == ScriptType.Null)
|
||||||
return null;
|
return null;
|
||||||
|
if (type.BaseType == null)
|
||||||
|
return type.Type;
|
||||||
while (type.Type == null)
|
while (type.Type == null)
|
||||||
type = type.BaseType;
|
type = type.BaseType;
|
||||||
return type.Type;
|
return type.Type;
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ namespace FlaxEditor.Surface
|
|||||||
return scriptType.GetGenericTypeDefinition() == typeof(Dictionary<,>);
|
return scriptType.GetGenericTypeDefinition() == typeof(Dictionary<,>);
|
||||||
}
|
}
|
||||||
var managedType = TypeUtils.GetType(scriptType);
|
var managedType = TypeUtils.GetType(scriptType);
|
||||||
return !TypeUtils.IsDelegate(managedType);
|
return managedType != null && !TypeUtils.IsDelegate(managedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool IsValidVisualScriptFunctionType(ScriptType scriptType)
|
internal static bool IsValidVisualScriptFunctionType(ScriptType scriptType)
|
||||||
@@ -408,7 +408,7 @@ namespace FlaxEditor.Surface
|
|||||||
if (scriptType.IsGenericType || scriptType.IsStatic || !scriptType.IsPublic || scriptType.HasAttribute(typeof(HideInEditorAttribute), true))
|
if (scriptType.IsGenericType || scriptType.IsStatic || !scriptType.IsPublic || scriptType.HasAttribute(typeof(HideInEditorAttribute), true))
|
||||||
return false;
|
return false;
|
||||||
var managedType = TypeUtils.GetType(scriptType);
|
var managedType = TypeUtils.GetType(scriptType);
|
||||||
return !TypeUtils.IsDelegate(managedType);
|
return managedType != null && !TypeUtils.IsDelegate(managedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static string GetVisualScriptTypeDescription(ScriptType type)
|
internal static string GetVisualScriptTypeDescription(ScriptType type)
|
||||||
|
|||||||
@@ -878,7 +878,7 @@ namespace FlaxEditor.Windows
|
|||||||
Message = _outMessages[i],
|
Message = _outMessages[i],
|
||||||
};
|
};
|
||||||
_entries.Add(entry);
|
_entries.Add(entry);
|
||||||
_outMessages[i] = null;
|
_outMessages[i] = null; // Prevent passing old strings back to native side
|
||||||
_isDirty = true;
|
_isDirty = true;
|
||||||
}
|
}
|
||||||
} while (logCount != 0);
|
} while (logCount != 0);
|
||||||
|
|||||||
@@ -269,7 +269,7 @@ namespace FlaxEngine
|
|||||||
internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
|
internal static partial bool Internal_HasConnection(ref AnimationGraph.CustomNode.Context context, int boxId);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetInputValue")]
|
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetInputValue")]
|
||||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ManagedHandleMarshaller))]
|
[return: MarshalUsing(typeof(FlaxEngine.Interop.AsManagedHandleMarshaller))]
|
||||||
internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
|
internal static partial object Internal_GetInputValue(ref AnimationGraph.CustomNode.Context context, int boxId);
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetOutputImpulseData")]
|
[LibraryImport("FlaxEngine", EntryPoint = "AnimGraphInternal_GetOutputImpulseData")]
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ static_assert(sizeof(InternalImpulse) == sizeof(AnimGraphImpulse), "Please updat
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* context, int32 boxId)
|
DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* context, int32 boxId)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
const auto box = context->Node->TryGetBox(boxId);
|
const auto box = context->Node->TryGetBox(boxId);
|
||||||
if (box == nullptr)
|
if (box == nullptr)
|
||||||
DebugLog::ThrowArgumentOutOfRange("boxId");
|
DebugLog::ThrowArgumentOutOfRange("boxId");
|
||||||
@@ -55,6 +56,7 @@ DEFINE_INTERNAL_CALL(bool) AnimGraphInternal_HasConnection(InternalContext* cont
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
|
DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext* context, int32 boxId)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
const auto box = context->Node->TryGetBox(boxId);
|
const auto box = context->Node->TryGetBox(boxId);
|
||||||
if (box == nullptr)
|
if (box == nullptr)
|
||||||
DebugLog::ThrowArgumentOutOfRange("boxId");
|
DebugLog::ThrowArgumentOutOfRange("boxId");
|
||||||
@@ -72,6 +74,7 @@ DEFINE_INTERNAL_CALL(MObject*) AnimGraphInternal_GetInputValue(InternalContext*
|
|||||||
|
|
||||||
DEFINE_INTERNAL_CALL(AnimGraphImpulse*) AnimGraphInternal_GetOutputImpulseData(InternalContext* context)
|
DEFINE_INTERNAL_CALL(AnimGraphImpulse*) AnimGraphInternal_GetOutputImpulseData(InternalContext* context)
|
||||||
{
|
{
|
||||||
|
PLATFORM_DEBUG_BREAK;
|
||||||
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
|
const auto nodes = context->Node->GetNodes(context->GraphExecutor);
|
||||||
context->GraphExecutor->InitNodes(nodes);
|
context->GraphExecutor->InitNodes(nodes);
|
||||||
return nodes;
|
return nodes;
|
||||||
|
|||||||
@@ -2441,10 +2441,14 @@ void AnimGraphExecutor::ProcessGroupAnimation(Box* boxBase, Node* nodeBase, Valu
|
|||||||
{
|
{
|
||||||
if (bucket.LoopsLeft == 0)
|
if (bucket.LoopsLeft == 0)
|
||||||
{
|
{
|
||||||
// End playing animation
|
// End playing animation and reset bucket params
|
||||||
value = tryGetValue(node->GetBox(1), Value::Null);
|
value = tryGetValue(node->GetBox(1), Value::Null);
|
||||||
bucket.Index = -1;
|
bucket.Index = -1;
|
||||||
slot.Animation = nullptr;
|
slot.Animation = nullptr;
|
||||||
|
bucket.TimePosition = 0.0f;
|
||||||
|
bucket.BlendInPosition = 0.0f;
|
||||||
|
bucket.BlendOutPosition = 0.0f;
|
||||||
|
bucket.LoopsDone = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2553,9 +2557,15 @@ void AnimGraphExecutor::ProcessGroupFunction(Box* boxBase, Node* node, Value& va
|
|||||||
// Function Input
|
// Function Input
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
|
// Skip when graph is too small (eg. preview) and fallback with default value from the function graph
|
||||||
|
if (context.GraphStack.Count() < 2)
|
||||||
|
{
|
||||||
|
value = tryGetValue(node->TryGetBox(1), Value::Zero);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the function call
|
// Find the function call
|
||||||
AnimGraphNode* functionCallNode = nullptr;
|
AnimGraphNode* functionCallNode = nullptr;
|
||||||
ASSERT(context.GraphStack.Count() >= 2);
|
|
||||||
Graph* graph;
|
Graph* graph;
|
||||||
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
for (int32 i = context.CallStack.Count() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -962,7 +962,7 @@ void SceneAnimationPlayer::Tick(SceneAnimation* anim, float time, float dt, int3
|
|||||||
else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType))
|
else if (!MCore::Type::IsPointer(valueType) && !MCore::Type::IsReference(valueType))
|
||||||
{
|
{
|
||||||
if (boxed)
|
if (boxed)
|
||||||
Platform::MemoryCopy(value, MCore::Object::Unbox(boxed), valueSize);
|
MCore::Object::Unbox(boxed, value);
|
||||||
else
|
else
|
||||||
Platform::MemoryClear(value, valueSize);
|
Platform::MemoryClear(value, valueSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -658,7 +658,10 @@ public:
|
|||||||
--_count;
|
--_count;
|
||||||
T* data = _allocation.Get();
|
T* data = _allocation.Get();
|
||||||
if (index < _count)
|
if (index < _count)
|
||||||
Memory::MoveAssignItems(data + index, data + (index + 1), _count - index);
|
{
|
||||||
|
for (int32 i = index; i < _count; i++)
|
||||||
|
data[i] = MoveTemp(data[i + 1]);
|
||||||
|
}
|
||||||
Memory::DestructItems(data + _count, 1);
|
Memory::DestructItems(data + _count, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -409,27 +409,36 @@ protected:
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Rebuild entire table completely
|
// Rebuild entire table completely
|
||||||
|
const int32 elementsCount = _elementsCount;
|
||||||
|
const int32 oldSize = _size;
|
||||||
AllocationData oldAllocation;
|
AllocationData oldAllocation;
|
||||||
AllocationUtils::MoveToEmpty<BucketType, AllocationType>(oldAllocation, _allocation, _size, _size);
|
AllocationUtils::MoveToEmpty<BucketType, AllocationType>(oldAllocation, _allocation, oldSize, oldSize);
|
||||||
_allocation.Allocate(_size);
|
_allocation.Allocate(_size);
|
||||||
BucketType* data = _allocation.Get();
|
BucketType* data = _allocation.Get();
|
||||||
for (int32 i = 0; i < _size; ++i)
|
for (int32 i = 0; i < oldSize; ++i)
|
||||||
data[i]._state = HashSetBucketState::Empty;
|
data[i]._state = HashSetBucketState::Empty;
|
||||||
BucketType* oldData = oldAllocation.Get();
|
BucketType* oldData = oldAllocation.Get();
|
||||||
FindPositionResult pos;
|
FindPositionResult pos;
|
||||||
for (int32 i = 0; i < _size; ++i)
|
for (int32 i = 0; i < oldSize; ++i)
|
||||||
{
|
{
|
||||||
BucketType& oldBucket = oldData[i];
|
BucketType& oldBucket = oldData[i];
|
||||||
if (oldBucket.IsOccupied())
|
if (oldBucket.IsOccupied())
|
||||||
{
|
{
|
||||||
FindPosition(oldBucket.GetKey(), pos);
|
FindPosition(oldBucket.GetKey(), pos);
|
||||||
ASSERT(pos.FreeSlotIndex != -1);
|
if (pos.FreeSlotIndex == -1)
|
||||||
|
{
|
||||||
|
// Grow and retry to handle pathological cases (eg. heavy collisions)
|
||||||
|
EnsureCapacity(_size + 1, true);
|
||||||
|
FindPosition(oldBucket.GetKey(), pos);
|
||||||
|
ASSERT(pos.FreeSlotIndex != -1);
|
||||||
|
}
|
||||||
BucketType& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
BucketType& bucket = _allocation.Get()[pos.FreeSlotIndex];
|
||||||
bucket = MoveTemp(oldBucket);
|
bucket = MoveTemp(oldBucket);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int32 i = 0; i < _size; ++i)
|
for (int32 i = 0; i < oldSize; ++i)
|
||||||
oldData[i].Free();
|
oldData[i].Free();
|
||||||
|
_elementsCount = elementsCount;
|
||||||
}
|
}
|
||||||
_deletedCount = 0;
|
_deletedCount = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
|
|
||||||
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
|
#define DLLEXPORT __attribute__((__visibility__("default")))
|
||||||
#define DLLIMPORT
|
#define DLLIMPORT
|
||||||
|
#define USED __attribute__((used))
|
||||||
#define THREADLOCAL __thread
|
#define THREADLOCAL __thread
|
||||||
#define STDCALL __attribute__((stdcall))
|
#define STDCALL __attribute__((stdcall))
|
||||||
#define CDECL __attribute__((cdecl))
|
#define CDECL __attribute__((cdecl))
|
||||||
@@ -19,7 +20,7 @@
|
|||||||
#define PACK_BEGIN()
|
#define PACK_BEGIN()
|
||||||
#define PACK_END() __attribute__((__packed__))
|
#define PACK_END() __attribute__((__packed__))
|
||||||
#define ALIGN_BEGIN(_align)
|
#define ALIGN_BEGIN(_align)
|
||||||
#define ALIGN_END(_align) __attribute__( (aligned(_align) ) )
|
#define ALIGN_END(_align) __attribute__((aligned(_align)))
|
||||||
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
||||||
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS \
|
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS \
|
||||||
_Pragma("clang diagnostic push") \
|
_Pragma("clang diagnostic push") \
|
||||||
@@ -37,8 +38,9 @@
|
|||||||
|
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
|
|
||||||
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
|
#define DLLEXPORT __attribute__((__visibility__("default")))
|
||||||
#define DLLIMPORT
|
#define DLLIMPORT
|
||||||
|
#define USED __attribute__((used))
|
||||||
#define THREADLOCAL __thread
|
#define THREADLOCAL __thread
|
||||||
#define STDCALL __attribute__((stdcall))
|
#define STDCALL __attribute__((stdcall))
|
||||||
#define CDECL __attribute__((cdecl))
|
#define CDECL __attribute__((cdecl))
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
#define PACK_BEGIN()
|
#define PACK_BEGIN()
|
||||||
#define PACK_END() __attribute__((__packed__))
|
#define PACK_END() __attribute__((__packed__))
|
||||||
#define ALIGN_BEGIN(_align)
|
#define ALIGN_BEGIN(_align)
|
||||||
#define ALIGN_END(_align) __attribute__( (aligned(_align) ) )
|
#define ALIGN_END(_align) __attribute__((aligned(_align)))
|
||||||
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
#define OFFSET_OF(X, Y) __builtin_offsetof(X, Y)
|
||||||
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
#define PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||||
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
#define PRAGMA_ENABLE_DEPRECATION_WARNINGS
|
||||||
@@ -67,6 +69,7 @@
|
|||||||
|
|
||||||
#define DLLEXPORT __declspec(dllexport)
|
#define DLLEXPORT __declspec(dllexport)
|
||||||
#define DLLIMPORT __declspec(dllimport)
|
#define DLLIMPORT __declspec(dllimport)
|
||||||
|
#define USED
|
||||||
#define THREADLOCAL __declspec(thread)
|
#define THREADLOCAL __declspec(thread)
|
||||||
#define STDCALL __stdcall
|
#define STDCALL __stdcall
|
||||||
#define CDECL __cdecl
|
#define CDECL __cdecl
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace FlaxEditor.Content.Settings
|
|||||||
/// <returns>The layers.</returns>
|
/// <returns>The layers.</returns>
|
||||||
public static string[] GetCurrentLayers()
|
public static string[] GetCurrentLayers()
|
||||||
{
|
{
|
||||||
return GetCurrentLayers(out int _);
|
return Internal_GetCurrentLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -56,7 +56,7 @@ namespace FlaxEditor.Content.Settings
|
|||||||
}
|
}
|
||||||
|
|
||||||
[LibraryImport("FlaxEngine", EntryPoint = "LayersAndTagsSettingsInternal_GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
[LibraryImport("FlaxEngine", EntryPoint = "LayersAndTagsSettingsInternal_GetCurrentLayers", StringMarshalling = StringMarshalling.Custom, StringMarshallingCustomType = typeof(FlaxEngine.Interop.StringMarshaller))]
|
||||||
[return: MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = "layerCount")]
|
[return: MarshalUsing(typeof(FlaxEngine.Interop.NativeSpanMarshaller<string, FlaxEngine.Interop.NativeString>), ConstantElementCount = FlaxEngine.Interop.MarshallerFlags.SkipDisposeElements)]
|
||||||
internal static partial string[] GetCurrentLayers(out int layerCount);
|
internal static partial string[] Internal_GetCurrentLayers();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ void Log::Logger::Write(const StringView& msg)
|
|||||||
IsDuringLog = true;
|
IsDuringLog = true;
|
||||||
|
|
||||||
// Send message to standard process output
|
// Send message to standard process output
|
||||||
if (CommandLine::Options.Std.IsTrue())
|
if (!CommandLine::Options.Std.IsFalse())
|
||||||
{
|
{
|
||||||
#if PLATFORM_TEXT_IS_CHAR16
|
#if PLATFORM_TEXT_IS_CHAR16
|
||||||
StringAnsi ansi(msg);
|
StringAnsi ansi(msg);
|
||||||
|
|||||||
@@ -678,7 +678,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in BoundingBox other)
|
public bool Equals(in BoundingBox other)
|
||||||
{
|
{
|
||||||
return Minimum == other.Minimum && Maximum == other.Maximum;
|
return Minimum.Equals(other.Minimum) && Maximum.Equals(other.Maximum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in BoundingFrustum other)
|
public bool Equals(in BoundingFrustum other)
|
||||||
{
|
{
|
||||||
return pMatrix == other.pMatrix;
|
return pMatrix.Equals(other.pMatrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -492,7 +492,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in BoundingSphere other)
|
public bool Equals(in BoundingSphere other)
|
||||||
{
|
{
|
||||||
return Center == other.Center && Radius == other.Radius;
|
return Center.Equals(other.Center) && Radius.Equals(other.Radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Color other)
|
public bool Equals(in Color other)
|
||||||
{
|
{
|
||||||
return R == other.R && G == other.G && B == other.B && A == other.A;
|
return R.Equals(other.R) && G.Equals(other.G) && B.Equals(other.B) && A.Equals(other.A);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -1582,7 +1582,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Double2 other)
|
public bool Equals(in Double2 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y;
|
return X.Equals(other.X) && Y.Equals(other.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1880,7 +1880,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Double3 other)
|
public bool Equals(in Double3 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1379,7 +1379,7 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Double4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Double4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Double4 other)
|
public bool Equals(in Double4 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1658,7 +1658,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Float2 other)
|
public bool Equals(in Float2 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y;
|
return X.Equals(other.X) && Y.Equals(other.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1912,7 +1912,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Float3 other)
|
public bool Equals(in Float3 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1419,7 +1419,7 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Float4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Float4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Float4 other)
|
public bool Equals(in Float4 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ namespace FlaxEngine
|
|||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public static double InverseLerp(double a, double b, double value)
|
public static double InverseLerp(double a, double b, double value)
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a.Equals(b))
|
||||||
return 0d;
|
return 0d;
|
||||||
return Saturate((value - a) / (b - a));
|
return Saturate((value - a) / (b - a));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ namespace FlaxEngine
|
|||||||
/// <param name="value"></param>
|
/// <param name="value"></param>
|
||||||
public static float InverseLerp(float a, float b, float value)
|
public static float InverseLerp(float a, float b, float value)
|
||||||
{
|
{
|
||||||
if (a == b)
|
if (a.Equals(b))
|
||||||
return 0f;
|
return 0f;
|
||||||
return Saturate((value - a) / (b - a));
|
return Saturate((value - a) / (b - a));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3236,22 +3236,22 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Matrix" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Matrix" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Matrix other)
|
public bool Equals(in Matrix other)
|
||||||
{
|
{
|
||||||
return other.M11 == M11 &&
|
return other.M11.Equals(M11) &&
|
||||||
other.M12 == M12 &&
|
other.M12.Equals(M12) &&
|
||||||
other.M13 == M13 &&
|
other.M13.Equals(M13) &&
|
||||||
other.M14 == M14 &&
|
other.M14.Equals(M14) &&
|
||||||
other.M21 == M21 &&
|
other.M21.Equals(M21) &&
|
||||||
other.M22 == M22 &&
|
other.M22.Equals(M22) &&
|
||||||
other.M23 == M23 &&
|
other.M23.Equals(M23) &&
|
||||||
other.M24 == M24 &&
|
other.M24.Equals(M24) &&
|
||||||
other.M31 == M31 &&
|
other.M31.Equals(M31) &&
|
||||||
other.M32 == M32 &&
|
other.M32.Equals(M32) &&
|
||||||
other.M33 == M33 &&
|
other.M33.Equals(M33) &&
|
||||||
other.M34 == M34 &&
|
other.M34.Equals(M34) &&
|
||||||
other.M41 == M41 &&
|
other.M41.Equals(M41) &&
|
||||||
other.M42 == M42 &&
|
other.M42.Equals(M42) &&
|
||||||
other.M43 == M43 &&
|
other.M43.Equals(M43) &&
|
||||||
other.M44 == M44;
|
other.M44.Equals(M44);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Matrix2x2"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Matrix2x2"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Matrix2x2 other)
|
public bool Equals(in Matrix2x2 other)
|
||||||
{
|
{
|
||||||
return M11 == other.M11 && M12 == other.M12 && M21 == other.M21 && M22 == other.M22;
|
return M11.Equals(other.M11) && M12.Equals(other.M12) && M21.Equals(other.M21) && M22.Equals(other.M22);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -2125,15 +2125,15 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Matrix3x3"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Matrix3x3"/> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Matrix3x3 other)
|
public bool Equals(in Matrix3x3 other)
|
||||||
{
|
{
|
||||||
return M11 == other.M11 &&
|
return M11.Equals(other.M11) &&
|
||||||
M12 == other.M12 &&
|
M12.Equals(other.M12) &&
|
||||||
M13 == other.M13 &&
|
M13.Equals(other.M13) &&
|
||||||
M21 == other.M21 &&
|
M21.Equals(other.M21) &&
|
||||||
M22 == other.M22 &&
|
M22.Equals(other.M22) &&
|
||||||
M23 == other.M23 &&
|
M23.Equals(other.M23) &&
|
||||||
M31 == other.M31 &&
|
M31.Equals(other.M31) &&
|
||||||
M32 == other.M32 &&
|
M32.Equals(other.M32) &&
|
||||||
M33 == other.M33;
|
M33.Equals(other.M33);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in OrientedBoundingBox value)
|
public bool Equals(in OrientedBoundingBox value)
|
||||||
{
|
{
|
||||||
return Extents == value.Extents && Transformation == value.Transformation;
|
return Extents.Equals(value.Extents) && Transformation.Equals(value.Transformation);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -587,7 +587,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Plane other)
|
public bool Equals(in Plane other)
|
||||||
{
|
{
|
||||||
return Normal == other.Normal && D == other.D;
|
return Normal.Equals(other.Normal) && D.Equals(other.D);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1714,7 +1714,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Quaternion other)
|
public bool Equals(in Quaternion other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Ray other)
|
public bool Equals(in Ray other)
|
||||||
{
|
{
|
||||||
return Position == other.Position && Direction == other.Direction;
|
return Position.Equals(other.Position) && Direction.Equals(other.Direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -499,7 +499,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Rectangle other)
|
public bool Equals(in Rectangle other)
|
||||||
{
|
{
|
||||||
return Location == other.Location && Size == other.Size;
|
return Location.Equals(other.Location) && Size.Equals(other.Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -705,7 +705,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Transform other)
|
public bool Equals(in Transform other)
|
||||||
{
|
{
|
||||||
return Translation == other.Translation && Orientation == other.Orientation && Scale == other.Scale;
|
return Translation.Equals(other.Translation) && Orientation.Equals(other.Orientation) && Scale.Equals(other.Scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1782,7 +1782,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Vector2 other)
|
public bool Equals(in Vector2 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y;
|
return X.Equals(other.X) && Y.Equals(other.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -2141,7 +2141,7 @@ namespace FlaxEngine
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(in Vector3 other)
|
public bool Equals(in Vector3 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1493,7 +1493,7 @@ namespace FlaxEngine
|
|||||||
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if the specified <see cref="Vector4" /> is equal to this instance; otherwise, <c>false</c>.</returns>
|
||||||
public bool Equals(in Vector4 other)
|
public bool Equals(in Vector4 other)
|
||||||
{
|
{
|
||||||
return X == other.X && Y == other.Y && Z == other.Z && W == other.W;
|
return X.Equals(other.X) && Y.Equals(other.Y) && Z.Equals(other.Z) && W.Equals(other.W);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -18,9 +18,7 @@ namespace AllocationUtils
|
|||||||
capacity |= capacity >> 8;
|
capacity |= capacity >> 8;
|
||||||
capacity |= capacity >> 16;
|
capacity |= capacity >> 16;
|
||||||
uint64 capacity64 = (uint64)(capacity + 1) * 2;
|
uint64 capacity64 = (uint64)(capacity + 1) * 2;
|
||||||
if (capacity64 > MAX_int32)
|
return capacity64 >= MAX_int32 ? MAX_int32 : (int32)capacity64 / 2;
|
||||||
capacity64 = MAX_int32;
|
|
||||||
return (int32)capacity64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Aligns the input value to the next power of 2 to be used as bigger memory allocation block.
|
// Aligns the input value to the next power of 2 to be used as bigger memory allocation block.
|
||||||
|
|||||||
@@ -889,6 +889,11 @@ Variant::Variant(const Span<byte>& v)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Variant::Variant(const BytesContainer& v)
|
||||||
|
: Variant((const Span<byte>&)(v))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||||
#include "Engine/Content/Deprecated.h"
|
#include "Engine/Content/Deprecated.h"
|
||||||
Variant::Variant(const CommonValue& value)
|
Variant::Variant(const CommonValue& value)
|
||||||
@@ -4301,8 +4306,12 @@ void Variant::CopyStructure(void* src)
|
|||||||
if (MANAGED_GC_HANDLE && mclass->IsValueType())
|
if (MANAGED_GC_HANDLE && mclass->IsValueType())
|
||||||
{
|
{
|
||||||
MObject* instance = MCore::GCHandle::GetTarget(MANAGED_GC_HANDLE);
|
MObject* instance = MCore::GCHandle::GetTarget(MANAGED_GC_HANDLE);
|
||||||
void* data = MCore::Object::Unbox(instance);
|
PLATFORM_DEBUG_BREAK; // FIXME
|
||||||
Platform::MemoryCopy(data, src, mclass->GetInstanceSize());
|
MCore::GCHandle::Free(MANAGED_GC_HANDLE);
|
||||||
|
instance = MCore::Object::Box(src, mclass);
|
||||||
|
MANAGED_GC_HANDLE = *(MGCHandle*)&instance;
|
||||||
|
//void* data = MCore::Object::Unbox(instance);
|
||||||
|
//Platform::MemoryCopy(data, src, mclass->GetInstanceSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ struct CommonValue;
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
class AssetReference;
|
class AssetReference;
|
||||||
struct ScriptingTypeHandle;
|
struct ScriptingTypeHandle;
|
||||||
|
template<typename T>
|
||||||
|
class DataContainer;
|
||||||
|
typedef DataContainer<byte> BytesContainer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents an object type that can be interpreted as more than one type.
|
/// Represents an object type that can be interpreted as more than one type.
|
||||||
@@ -244,6 +247,7 @@ public:
|
|||||||
explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v);
|
explicit Variant(Dictionary<Variant, Variant, HeapAllocation>&& v);
|
||||||
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
|
explicit Variant(const Dictionary<Variant, Variant, HeapAllocation>& v);
|
||||||
explicit Variant(const Span<byte>& v);
|
explicit Variant(const Span<byte>& v);
|
||||||
|
explicit Variant(const BytesContainer& v);
|
||||||
explicit Variant(const CommonValue& v);
|
explicit Variant(const CommonValue& v);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "CommandLine.h"
|
#include "CommandLine.h"
|
||||||
#include "Engine/Core/Collections/Array.h"
|
#include "Engine/Core/Collections/Array.h"
|
||||||
#include "Engine/Core/Utilities.h"
|
#include "Engine/Core/Utilities.h"
|
||||||
|
#include "Engine/Core/Types/StringView.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
CommandLine::OptionsData CommandLine::Options;
|
CommandLine::OptionsData CommandLine::Options;
|
||||||
@@ -155,6 +156,7 @@ bool CommandLine::Parse(const Char* cmdLine)
|
|||||||
PARSE_BOOL_SWITCH("-clearcache ", ClearCache);
|
PARSE_BOOL_SWITCH("-clearcache ", ClearCache);
|
||||||
PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache);
|
PARSE_BOOL_SWITCH("-clearcooker ", ClearCookerCache);
|
||||||
PARSE_ARG_SWITCH("-project ", Project);
|
PARSE_ARG_SWITCH("-project ", Project);
|
||||||
|
PARSE_BOOL_SWITCH("-lastproject ", LastProject);
|
||||||
PARSE_BOOL_SWITCH("-new ", NewProject);
|
PARSE_BOOL_SWITCH("-new ", NewProject);
|
||||||
PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles);
|
PARSE_BOOL_SWITCH("-genprojectfiles ", GenProjectFiles);
|
||||||
PARSE_ARG_SWITCH("-build ", Build);
|
PARSE_ARG_SWITCH("-build ", Build);
|
||||||
@@ -169,3 +171,63 @@ bool CommandLine::Parse(const Char* cmdLine)
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CommandLine::ParseArguments(const StringView& cmdLine, Array<StringAnsi>& arguments)
|
||||||
|
{
|
||||||
|
int32 start = 0;
|
||||||
|
int32 quotesStart = -1;
|
||||||
|
int32 length = cmdLine.Length();
|
||||||
|
for (int32 i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
if (cmdLine[i] == ' ' && quotesStart == -1)
|
||||||
|
{
|
||||||
|
int32 count = i - start;
|
||||||
|
if (count > 0)
|
||||||
|
arguments.Add(StringAnsi(cmdLine.Substring(start, count)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
else if (cmdLine[i] == '\"')
|
||||||
|
{
|
||||||
|
if (quotesStart >= 0)
|
||||||
|
{
|
||||||
|
if (i + 1 < length && cmdLine[i + 1] != ' ')
|
||||||
|
{
|
||||||
|
// End quotes are in the middle of the current word,
|
||||||
|
// continue until the end of the current word.
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int32 offset = 1;
|
||||||
|
if (quotesStart == start && cmdLine[start] == '\"')
|
||||||
|
{
|
||||||
|
// Word starts and ends with quotes, only include the quoted content.
|
||||||
|
quotesStart++;
|
||||||
|
offset--;
|
||||||
|
}
|
||||||
|
else if (quotesStart != start)
|
||||||
|
{
|
||||||
|
// Start quotes in the middle of the word, include the whole word.
|
||||||
|
quotesStart = start;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 count = i - quotesStart + offset;
|
||||||
|
if (count > 0)
|
||||||
|
arguments.Add(StringAnsi(cmdLine.Substring(quotesStart, count)));
|
||||||
|
start = i + 1;
|
||||||
|
}
|
||||||
|
quotesStart = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
quotesStart = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const int32 count = length - start;
|
||||||
|
if (count > 0)
|
||||||
|
arguments.Add(StringAnsi(cmdLine.Substring(start, count)));
|
||||||
|
if (quotesStart >= 0)
|
||||||
|
return true; // Missing last closing quote
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "Engine/Core/Types/String.h"
|
#include "Engine/Core/Types/String.h"
|
||||||
#include "Engine/Core/Types/Nullable.h"
|
#include "Engine/Core/Types/Nullable.h"
|
||||||
|
#include "Engine/Core/Collections/Array.h"
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command line options helper.
|
/// Command line options helper.
|
||||||
@@ -147,6 +148,11 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
String Project;
|
String Project;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// -lastproject (Opens the last project)
|
||||||
|
/// </summary>
|
||||||
|
Nullable<bool> LastProject;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// -new (generates the project files inside the specified project folder or uses current workspace folder)
|
/// -new (generates the project files inside the specified project folder or uses current workspace folder)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -214,4 +220,12 @@ public:
|
|||||||
/// <param name="cmdLine">The command line.</param>
|
/// <param name="cmdLine">The command line.</param>
|
||||||
/// <returns>True if failed, otherwise false.</returns>
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
static bool Parse(const Char* cmdLine);
|
static bool Parse(const Char* cmdLine);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the command line arguments string into string list of arguments.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cmdLine">The command line.</param>
|
||||||
|
/// <param name="arguments">The parsed arguments</param>
|
||||||
|
/// <returns>True if failed, otherwise false.</returns>
|
||||||
|
static bool ParseArguments(const StringView& cmdLine, Array<StringAnsi>& arguments);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -183,11 +183,11 @@ namespace FlaxEngine.Interop
|
|||||||
if (returnType == typeof(string))
|
if (returnType == typeof(string))
|
||||||
return ManagedString.ToNative/*Weak*/(Unsafe.As<string>(returnObject));
|
return ManagedString.ToNative/*Weak*/(Unsafe.As<string>(returnObject));
|
||||||
if (returnType == typeof(IntPtr))
|
if (returnType == typeof(IntPtr))
|
||||||
return (IntPtr)(object)returnObject;
|
return (IntPtr)returnObject;
|
||||||
if (returnType == typeof(ManagedHandle))
|
if (returnType == typeof(ManagedHandle))
|
||||||
return ManagedHandle.ToIntPtr((ManagedHandle)(object)returnObject);
|
return ManagedHandle.ToIntPtr((ManagedHandle)returnObject);
|
||||||
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
if (returnType == typeof(Type) || returnType == typeof(TypeHolder))
|
||||||
return returnObject != null ? ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject))) : IntPtr.Zero;
|
return ManagedHandle.ToIntPtr(GetTypeManagedHandle(Unsafe.As<Type>(returnObject)));
|
||||||
if (returnType.IsArray)
|
if (returnType.IsArray)
|
||||||
{
|
{
|
||||||
var elementType = returnType.GetElementType();
|
var elementType = returnType.GetElementType();
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||||
|
#pragma warning disable CS0162
|
||||||
#define USE_CONCURRENT_DICT
|
#define USE_CONCURRENT_DICT
|
||||||
#define USE_GCHANDLE
|
#define USE_GCHANDLE
|
||||||
|
//#define TRACK_HANDLES
|
||||||
|
|
||||||
#if USE_NETCORE
|
#if USE_NETCORE
|
||||||
using System;
|
using System;
|
||||||
@@ -310,20 +311,24 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty);
|
internal static ManagedHandle EmptyStringHandle = ManagedHandle.Alloc(string.Empty);
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerStepThrough]
|
//[System.Diagnostics.DebuggerStepThrough]
|
||||||
public static unsafe IntPtr ToNative(string str)
|
public static unsafe IntPtr ToNative(string str)
|
||||||
{
|
{
|
||||||
if (str == null)
|
if (str == null)
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
else if (str == string.Empty)
|
//else if (str == string.Empty)
|
||||||
return ManagedHandle.ToIntPtr(EmptyStringHandle);
|
// return ManagedHandle.ToIntPtr(EmptyStringHandle);
|
||||||
Assert.IsTrue(str.Length > 0);
|
//return ManagedHandle.ToIntPtr(str);
|
||||||
return ManagedHandle.ToIntPtr(str);
|
|
||||||
|
NativeString* nativeString = (NativeString*)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeString>(), 16);
|
||||||
|
*nativeString = new NativeString(str);
|
||||||
|
return (IntPtr)nativeString;
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerStepThrough]
|
//[System.Diagnostics.DebuggerStepThrough]
|
||||||
public static unsafe IntPtr ToNativeWeak(string str)
|
public static unsafe IntPtr ToNativeWeak(string str)
|
||||||
{
|
{
|
||||||
|
throw new Exception("not used");
|
||||||
if (str == null)
|
if (str == null)
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
else if (str == string.Empty)
|
else if (str == string.Empty)
|
||||||
@@ -332,20 +337,39 @@ namespace FlaxEngine.Interop
|
|||||||
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
|
return ManagedHandle.ToIntPtr(str, GCHandleType.Weak);
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerStepThrough]
|
//[System.Diagnostics.DebuggerStepThrough]
|
||||||
public static string ToManaged(IntPtr ptr)
|
public static unsafe string ToManaged(IntPtr ptr)
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
if (ptr == IntPtr.Zero)
|
||||||
return null;
|
return null;
|
||||||
return Unsafe.As<string>(ManagedHandle.FromIntPtr(ptr).Target);
|
//return Unsafe.As<string>(ManagedHandle.FromIntPtr(ptr).Target);
|
||||||
|
NativeString* str = (NativeString*)ptr.ToPointer();
|
||||||
|
return str->ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.Diagnostics.DebuggerStepThrough]
|
//[System.Diagnostics.DebuggerStepThrough]
|
||||||
public static void Free(IntPtr ptr)
|
public static unsafe void Free(IntPtr ptr)
|
||||||
{
|
{
|
||||||
if (ptr == IntPtr.Zero)
|
if (ptr == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
|
//ManagedHandle handle = ManagedHandle.FromIntPtr(ptr);
|
||||||
|
//if (handle == EmptyStringHandle)
|
||||||
|
// return;
|
||||||
|
//handle.Free();
|
||||||
|
Free((NativeString*)ptr.ToPointer());
|
||||||
|
}
|
||||||
|
|
||||||
|
//[System.Diagnostics.DebuggerStepThrough]
|
||||||
|
public static unsafe void Free(NativeString* str)
|
||||||
|
{
|
||||||
|
if (str->Data != null)
|
||||||
|
NativeMemory.AlignedFree(str->Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[System.Diagnostics.DebuggerStepThrough]
|
||||||
|
public static void Free(ManagedHandle handle)
|
||||||
|
{
|
||||||
|
throw new Exception("not used");
|
||||||
if (handle == EmptyStringHandle)
|
if (handle == EmptyStringHandle)
|
||||||
return;
|
return;
|
||||||
handle.Free();
|
handle.Free();
|
||||||
@@ -363,31 +387,48 @@ namespace FlaxEngine.Interop
|
|||||||
#if USE_GCHANDLE
|
#if USE_GCHANDLE
|
||||||
private GCHandle handle;
|
private GCHandle handle;
|
||||||
|
|
||||||
|
#if TRACK_HANDLES
|
||||||
private static HashSet<IntPtr> _weakHandles = new HashSet<nint>();
|
private static HashSet<IntPtr> _weakHandles = new HashSet<nint>();
|
||||||
private static Dictionary<IntPtr, string> _handles = new();
|
private static ConcurrentDictionary<IntPtr, string> _handles = new();
|
||||||
private static Dictionary<IntPtr, string> _handles2 = new();
|
private static ConcurrentDictionary<IntPtr, string> _handles2 = new();
|
||||||
|
private static long _allocations = 0;
|
||||||
|
private static long _deallocations = 0;
|
||||||
|
|
||||||
|
public static long Allocations => Interlocked.Read(ref _allocations);
|
||||||
|
public static long Deallocations => Interlocked.Read(ref _deallocations);
|
||||||
|
#else
|
||||||
|
public static long Allocations => 0;
|
||||||
|
public static long Deallocations => 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private ManagedHandle(IntPtr handle) => this.handle = GCHandle.FromIntPtr(handle);
|
private ManagedHandle(IntPtr handle) => this.handle = GCHandle.FromIntPtr(handle);
|
||||||
|
|
||||||
|
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private ManagedHandle(object value, GCHandleType type) //=> handle = GCHandle.Alloc(value, type);
|
private ManagedHandle(object value, GCHandleType type) //=> handle = GCHandle.Alloc(value, type);
|
||||||
{
|
{
|
||||||
if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
#if TRACK_HANDLES
|
||||||
|
/*if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
||||||
{
|
{
|
||||||
type = GCHandleType.Normal;
|
type = GCHandleType.Normal;
|
||||||
}
|
}*/
|
||||||
|
#endif
|
||||||
handle = GCHandle.Alloc(value, type);
|
handle = GCHandle.Alloc(value, type);
|
||||||
if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
#if TRACK_HANDLES
|
||||||
|
/*if (type == GCHandleType.Weak || type == GCHandleType.WeakTrackResurrection)
|
||||||
_weakHandles.Add((IntPtr)handle);
|
_weakHandles.Add((IntPtr)handle);
|
||||||
else if (_handles.Count < 14000)
|
else if (_handles.Count < 14000)
|
||||||
_handles.Add((IntPtr)handle, value?.GetType().FullName ?? "");
|
_handles.TryAdd((IntPtr)handle, value?.GetType().FullName ?? "");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (_handles2.Count > 12)
|
if (_handles2.Count > 12)
|
||||||
type = type;
|
type = type;
|
||||||
if (value?.GetType() == typeof(string))
|
if (value?.GetType() == typeof(string))
|
||||||
type = type;
|
type = type;
|
||||||
_handles2.Add((IntPtr)handle, value?.GetType().FullName ?? "");
|
_handles2.TryAdd((IntPtr)handle, value?.GetType().FullName ?? "");
|
||||||
}
|
}*/
|
||||||
|
Interlocked.Increment(ref _allocations);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
private IntPtr handle;
|
private IntPtr handle;
|
||||||
@@ -408,28 +449,40 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
if ((IntPtr)handle == IntPtr.Zero)
|
if ((IntPtr)handle == IntPtr.Zero)
|
||||||
return;
|
return;
|
||||||
if (_weakHandles.Remove((IntPtr)handle))
|
#if TRACK_HANDLES
|
||||||
|
/*if (_weakHandles.Remove((IntPtr)handle))
|
||||||
{
|
{
|
||||||
if (!handle.IsAllocated)
|
if (!handle.IsAllocated)
|
||||||
handle = handle;
|
handle = handle;
|
||||||
handle = handle;
|
handle = handle;
|
||||||
}
|
}
|
||||||
else if (_handles.Remove((IntPtr)handle))
|
else if (_handles.Remove((IntPtr)handle, out _))
|
||||||
{
|
{
|
||||||
handle = handle;
|
handle = handle;
|
||||||
}
|
}
|
||||||
else if (_handles2.Remove((IntPtr)handle))
|
else if (_handles2.Remove((IntPtr)handle, out _))
|
||||||
{
|
{
|
||||||
handle = handle;
|
handle = handle;
|
||||||
}
|
}*/
|
||||||
|
Interlocked.Increment(ref _deallocations);
|
||||||
|
#endif
|
||||||
handle.Free();
|
handle.Free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public object Target => handle.Target;
|
public object Target
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => handle.Target;
|
||||||
|
|
||||||
public bool IsAllocated => handle.IsAllocated;
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
set => handle.Target = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAllocated
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => handle.IsAllocated;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
public void Free()
|
public void Free()
|
||||||
{
|
{
|
||||||
@@ -477,22 +530,65 @@ namespace FlaxEngine.Interop
|
|||||||
public static IntPtr ToIntPtr(ManagedHandle value) => value.handle;
|
public static IntPtr ToIntPtr(ManagedHandle value) => value.handle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override int GetHashCode() => handle.GetHashCode();
|
public override int GetHashCode() => handle.GetHashCode();
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public override bool Equals(object obj) => obj is ManagedHandle other && handle == other.handle;
|
public override bool Equals(object obj) => obj is ManagedHandle other && handle == other.handle;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool Equals(ManagedHandle other) => handle == other.handle;
|
public bool Equals(ManagedHandle other) => handle == other.handle;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator ==(ManagedHandle a, ManagedHandle b) => a.handle == b.handle;
|
public static bool operator ==(ManagedHandle a, ManagedHandle b) => a.handle == b.handle;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static bool operator !=(ManagedHandle a, ManagedHandle b) => a.handle != b.handle;
|
public static bool operator !=(ManagedHandle a, ManagedHandle b) => a.handle != b.handle;
|
||||||
|
|
||||||
#if USE_GCHANDLE
|
#if USE_GCHANDLE
|
||||||
|
/// <summary>
|
||||||
|
/// A pool of shared managed handles used with short-lived temporary GCHandle allocations during interop.
|
||||||
|
/// </summary>
|
||||||
internal static class ManagedHandlePool
|
internal static class ManagedHandlePool
|
||||||
{
|
{
|
||||||
|
[ThreadStatic]
|
||||||
|
private static List<(bool InUse, ManagedHandle Handle)> __poolField;
|
||||||
|
private static List<(bool InUse, ManagedHandle Handle)> _pool => __poolField ??= [];
|
||||||
|
|
||||||
internal static void TryCollectWeakHandles(bool force = false)
|
internal static void TryCollectWeakHandles(bool force = false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static ManagedHandle Rent()
|
||||||
|
{
|
||||||
|
foreach (ref var tuple in CollectionsMarshal.AsSpan(_pool))
|
||||||
|
{
|
||||||
|
if (tuple.InUse)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tuple.InUse = true;
|
||||||
|
return tuple.Handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
var newTuple = (InUse: true, Array: new ManagedHandle());
|
||||||
|
_pool.Add(newTuple);
|
||||||
|
return newTuple.Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void Return(ManagedHandle handle)
|
||||||
|
{
|
||||||
|
foreach (ref var tuple in CollectionsMarshal.AsSpan(_pool))
|
||||||
|
{
|
||||||
|
if (tuple.Handle != handle)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
tuple.InUse = false;
|
||||||
|
handle.Target = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception("Tried to return non-pooled ManagedHandle");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -527,24 +527,51 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle NewArray(ManagedHandle typeHandle, long size)
|
internal static IntPtr NewArray(ManagedHandle typeHandle, long size)
|
||||||
{
|
{
|
||||||
Type elementType = Unsafe.As<TypeHolder>(typeHandle.Target);
|
Type elementType = Unsafe.As<TypeHolder>(typeHandle.Target);
|
||||||
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
Type marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
||||||
Type arrayType = ArrayFactory.GetArrayType(elementType);
|
Type arrayType = ArrayFactory.GetArrayType(elementType);
|
||||||
if (marshalledType.IsValueType)
|
if (marshalledType.IsValueType)
|
||||||
{
|
{
|
||||||
ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
|
IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeArrayTypeless>(), 16);
|
||||||
return ManagedHandle.Alloc(managedArray);
|
IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(RuntimeHelpers.SizeOf(marshalledType.TypeHandle) * size), 16);
|
||||||
|
Unsafe.Write<IntPtr>(arrayPtr.ToPointer(), dataPtr);
|
||||||
|
Unsafe.Write<long>(IntPtr.Add(arrayPtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), size);
|
||||||
|
|
||||||
|
return arrayPtr;
|
||||||
|
//ManagedArray managedArray = ManagedArray.AllocateNewArray((int)size, arrayType, marshalledType);
|
||||||
|
//return ManagedHandle.Alloc(managedArray);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Array arr = ArrayFactory.CreateArray(elementType, size);
|
/*Array arr = ArrayFactory.CreateArray(elementType, size);
|
||||||
ManagedArray managedArray = ManagedArray.WrapNewArray(arr, arrayType);
|
ManagedArray managedArray = ManagedArray.WrapNewArray(arr, arrayType);
|
||||||
return ManagedHandle.Alloc(managedArray);
|
return ManagedHandle.Alloc(managedArray);*/
|
||||||
|
IntPtr arrayPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)Unsafe.SizeOf<NativeArrayTypeless>(), 16);
|
||||||
|
IntPtr dataPtr = (IntPtr)NativeMemory.AlignedAlloc((UIntPtr)(Unsafe.SizeOf<IntPtr>() * size), 16);
|
||||||
|
Unsafe.Write<IntPtr>(arrayPtr.ToPointer(), dataPtr);
|
||||||
|
Unsafe.Write<long>(IntPtr.Add(arrayPtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), size);
|
||||||
|
|
||||||
|
return arrayPtr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void FreeArray(void* ptr)
|
||||||
|
{
|
||||||
|
if (ptr == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
|
||||||
|
array->Free();
|
||||||
|
/*ManagedArray managedArray = Unsafe.As<ManagedArray>(handle.Target);
|
||||||
|
if (managedArray.ElementType.IsValueType)
|
||||||
|
managedArray.Free();
|
||||||
|
else
|
||||||
|
managedArray.FreePooled();*/
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
|
internal static ManagedHandle GetArrayTypeFromElementType(ManagedHandle elementTypeHandle)
|
||||||
{
|
{
|
||||||
@@ -563,14 +590,15 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static IntPtr GetArrayPointer(ManagedHandle arrayHandle)
|
internal static IntPtr GetArrayPointer(void* ptr)
|
||||||
{
|
{
|
||||||
if (!arrayHandle.IsAllocated)
|
if (ptr == null)
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
|
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
|
||||||
if (managedArray.Length == 0)
|
if (array->Length == 0)
|
||||||
return IntPtr.Zero;
|
return IntPtr.Zero;
|
||||||
return managedArray.Pointer;
|
|
||||||
|
return (IntPtr)array->Data;
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -587,12 +615,16 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static int GetArrayLength(ManagedHandle arrayHandle)
|
internal static int GetArrayLength(void* ptr)
|
||||||
{
|
{
|
||||||
if (!arrayHandle.IsAllocated)
|
//if (ptr == null)
|
||||||
return 0;
|
// return 0;
|
||||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
|
NativeArrayTypeless* array = (NativeArrayTypeless*)ptr;
|
||||||
return managedArray.Length;
|
return array->Length;
|
||||||
|
/* if (!arrayHandle.IsAllocated)
|
||||||
|
return 0;
|
||||||
|
ManagedArray managedArray = Unsafe.As<ManagedArray>(arrayHandle.Target);
|
||||||
|
return managedArray.Length;*/
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -613,6 +645,12 @@ namespace FlaxEngine.Interop
|
|||||||
return ManagedString.ToNative/*Weak*/(new string(text, 0, length, System.Text.Encoding.UTF8));
|
return ManagedString.ToNative/*Weak*/(new string(text, 0, length, System.Text.Encoding.UTF8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly]
|
||||||
|
internal static void FreeString(NativeString* str)
|
||||||
|
{
|
||||||
|
ManagedString.Free(str);
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle GetObjectType(ManagedHandle handle)
|
internal static ManagedHandle GetObjectType(ManagedHandle handle)
|
||||||
{
|
{
|
||||||
@@ -656,8 +694,10 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a managed copy of the value, and stores it in a boxed reference.
|
/// Creates a managed converted copy of the unmanaged value, and boxes it in a managed handle.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="typeHandle">A handle to class type.</param>
|
||||||
|
/// <param name="valuePtr">A pointer to unmanaged value.</param>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
|
internal static ManagedHandle BoxValue(ManagedHandle typeHandle, IntPtr valuePtr)
|
||||||
{
|
{
|
||||||
@@ -667,16 +707,17 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the address of the boxed value type.
|
/// Writes the unboxed converted value to given address.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="objectHandle">A handle to boxed object.</param>
|
||||||
|
/// <param name="destinationPtr">The destination address for unboxed value.</param>
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static IntPtr UnboxValue(ManagedHandle handle)
|
internal static void UnboxValue(ManagedHandle objectHandle, IntPtr destinationPtr)
|
||||||
{
|
{
|
||||||
object value = handle.Target;
|
object value = objectHandle.Target;
|
||||||
|
Assert.IsNotNull(value, "Boxed value type can't be null.");
|
||||||
Type type = value.GetType();
|
Type type = value.GetType();
|
||||||
if (!type.IsValueType)
|
MarshalToNative(objectHandle.Target, destinationPtr, type);
|
||||||
return ManagedHandle.ToIntPtr(handle);
|
|
||||||
return ValueTypeUnboxer.GetPointer(value, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
@@ -744,7 +785,7 @@ namespace FlaxEngine.Interop
|
|||||||
for (int i = 0; i < numParams; i++)
|
for (int i = 0; i < numParams; i++)
|
||||||
{
|
{
|
||||||
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
IntPtr nativePtr = Unsafe.Read<IntPtr>((IntPtr.Add(paramPtr, sizeof(IntPtr) * i)).ToPointer());
|
||||||
methodParameters[i] = MarshalToManaged(nativePtr, methodHolder.parameterTypes[i]);
|
methodParameters[i] = MarshalToManaged2(nativePtr, methodHolder.parameterTypes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -766,8 +807,11 @@ namespace FlaxEngine.Interop
|
|||||||
{
|
{
|
||||||
// The internal exception thrown in MethodInfo.Invoke is caught here
|
// The internal exception thrown in MethodInfo.Invoke is caught here
|
||||||
Exception realException = exception;
|
Exception realException = exception;
|
||||||
if (exception.InnerException != null && exception.TargetSite.ReflectedType.Name == "MethodInvoker")
|
if (exception.InnerException != null &&
|
||||||
|
(exception.TargetSite.ReflectedType.Name == "MethodInvoker" || exception.TargetSite.ReflectedType.Name == "MethodBaseInvoker"))
|
||||||
|
{
|
||||||
realException = exception.InnerException;
|
realException = exception.InnerException;
|
||||||
|
}
|
||||||
|
|
||||||
if (exceptionPtr != IntPtr.Zero)
|
if (exceptionPtr != IntPtr.Zero)
|
||||||
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
Unsafe.Write<IntPtr>(exceptionPtr.ToPointer(), ManagedHandle.ToIntPtr(realException, GCHandleType.Weak));
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ using System.IO;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Buffers;
|
using System.Buffers;
|
||||||
|
using System.Runtime.InteropServices.Marshalling;
|
||||||
|
using FlaxEngine.Utilities;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace FlaxEngine.Interop
|
namespace FlaxEngine.Interop
|
||||||
{
|
{
|
||||||
@@ -188,6 +191,28 @@ namespace FlaxEngine.Interop
|
|||||||
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
|
return Marshal.GetFunctionPointerForDelegate<TDelegate>(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts array of GC Handles from native runtime to managed array.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">Array element type.</typeparam>
|
||||||
|
/// <param name="ptrArray">Input array.</param>
|
||||||
|
/// <param name="buffer">Cached memory allocation buffer to use for the result (if size fits).</param>
|
||||||
|
/// <returns>Output array.</returns>
|
||||||
|
public static T[] GCHandleArrayToManagedArray<T>(NativeArray<IntPtr> ptrArray, T[] buffer = null) where T : class
|
||||||
|
{
|
||||||
|
ReadOnlySpan<IntPtr> span = ptrArray.AsReadOnlySpan();
|
||||||
|
//if (buffer != null)
|
||||||
|
// buffer = buffer;
|
||||||
|
if (buffer == null || buffer.Length < ptrArray.Length)
|
||||||
|
buffer = new T[ptrArray.Length];
|
||||||
|
for (int i = 0; i < ptrArray.Length; i++)
|
||||||
|
{
|
||||||
|
IntPtr ptr = span[i];
|
||||||
|
buffer[i] = ptr != IntPtr.Zero ? (T)ManagedHandle.FromIntPtr(ptr).Target : default;
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts array of GC Handles from native runtime to managed array.
|
/// Converts array of GC Handles from native runtime to managed array.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -238,6 +263,24 @@ namespace FlaxEngine.Interop
|
|||||||
return ManagedArray.WrapNewArray(pointerArray, array.GetType());
|
return ManagedArray.WrapNewArray(pointerArray, array.GetType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts managed array wrapper into array of GC Handles for native runtime.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">Input array.</param>
|
||||||
|
/// <returns>Output array.</returns>
|
||||||
|
public static NativeArray<IntPtr> ManagedArrayToGCHandleWrappedArray<T>(T[] array)
|
||||||
|
{
|
||||||
|
NativeArray<IntPtr> pointerArray = new(array.Length);
|
||||||
|
for (int i = 0; i < array.Length; i++)
|
||||||
|
//foreach (var ptr in pointerArray.AsSpan())
|
||||||
|
{
|
||||||
|
pointerArray.Data[i] = array[i] != null ? ManagedHandle.ToIntPtr(array[i]) : IntPtr.Zero;
|
||||||
|
}
|
||||||
|
return pointerArray;
|
||||||
|
//IntPtr[] pointerArray = ManagedArrayToGCHandleArray(array);
|
||||||
|
//return ManagedArray.WrapNewArray(pointerArray, array.GetType());
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts array with a custom converter function for each element.
|
/// Converts array with a custom converter function for each element.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -270,6 +313,23 @@ namespace FlaxEngine.Interop
|
|||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts array with a custom converter function for each element.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TSrc">Input data type.</typeparam>
|
||||||
|
/// <typeparam name="TDst">Output data type.</typeparam>
|
||||||
|
/// <param name="src">The input array.</param>
|
||||||
|
/// <param name="convertFunc">Converter callback.</param>
|
||||||
|
/// <returns>The output array.</returns>
|
||||||
|
public static NativeArray<TDst> ConvertArrayNative<TSrc, TDst>(this Span<TSrc> src, Func<TSrc, TDst> convertFunc)
|
||||||
|
where TDst : unmanaged
|
||||||
|
{
|
||||||
|
NativeArray<TDst> dst = new(src.Length);
|
||||||
|
for (int i = 0; i < src.Length; i++)
|
||||||
|
dst.Data[i] = convertFunc(src[i]);
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Find <paramref name="assemblyName"/> among the scripting assemblies.</summary>
|
/// <summary>Find <paramref name="assemblyName"/> among the scripting assemblies.</summary>
|
||||||
/// <param name="assemblyName">The name to find</param>
|
/// <param name="assemblyName">The name to find</param>
|
||||||
/// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param>
|
/// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param>
|
||||||
@@ -353,6 +413,339 @@ namespace FlaxEngine.Interop
|
|||||||
internal static ConcurrentDictionary<Type, MarshalToNativeDelegate> toNativeMarshallers = new ConcurrentDictionary<Type, MarshalToNativeDelegate>(1, 3);
|
internal static ConcurrentDictionary<Type, MarshalToNativeDelegate> toNativeMarshallers = new ConcurrentDictionary<Type, MarshalToNativeDelegate>(1, 3);
|
||||||
internal static ConcurrentDictionary<Type, MarshalToNativeFieldDelegate> toNativeFieldMarshallers = new ConcurrentDictionary<Type, MarshalToNativeFieldDelegate>(1, 3);
|
internal static ConcurrentDictionary<Type, MarshalToNativeFieldDelegate> toNativeFieldMarshallers = new ConcurrentDictionary<Type, MarshalToNativeFieldDelegate>(1, 3);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
internal static ConcurrentDictionary<Type, (Type, Func<object, object>, Func<IntPtr, object>)> _marshallers = new(1, 3);
|
||||||
|
|
||||||
|
internal static class NewMarshalHelperValueType<TDest, TSource> where TSource : struct
|
||||||
|
{
|
||||||
|
internal static object NativeToManaged9(object src)
|
||||||
|
{
|
||||||
|
return NewMarshalHelper<TDest, TSource>.NativeToManaged9(ref Unsafe.Unbox<TSource>(src));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class NewMarshalHelperReferenceType<TDest, TSource> where TSource : class
|
||||||
|
{
|
||||||
|
internal static object NativeToManaged9(object src)
|
||||||
|
{
|
||||||
|
TSource tsrc = Unsafe.As<TSource>(src);
|
||||||
|
return NewMarshalHelper<TDest, TSource>.NativeToManaged9(ref tsrc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class NewMarshalHelper<TDest, TSource>
|
||||||
|
{
|
||||||
|
internal static Func<TSource, TDest> _nativeToManagedFunc;
|
||||||
|
internal static Type _pointerType;
|
||||||
|
|
||||||
|
internal static void Init(MethodInfo nativeToManagedMethod)
|
||||||
|
{
|
||||||
|
//Assert.IsNull(_nativeToManagedFunc);
|
||||||
|
|
||||||
|
//var internalType = nativeToManagedMethod.GetParameters()[0].ParameterType;
|
||||||
|
//var types = new Type[] { marshalType, internalType };
|
||||||
|
//var convertDelegate = method.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(types));
|
||||||
|
|
||||||
|
if (_nativeToManagedFunc == null && nativeToManagedMethod != null)
|
||||||
|
_nativeToManagedFunc = nativeToManagedMethod.CreateDelegate<Func<TSource, TDest>>();
|
||||||
|
|
||||||
|
_pointerType = typeof(TDest).MakePointerType();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static TDest NativeToManaged9(ref TSource src)
|
||||||
|
{
|
||||||
|
return _nativeToManagedFunc(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static object NativeToManagedIntPtr(TSource src)
|
||||||
|
{
|
||||||
|
// typeof(TSource) == typeof(IntPtr)
|
||||||
|
return _nativeToManagedFunc(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static object NativeToManagedPointer(IntPtr src)
|
||||||
|
{
|
||||||
|
//byte* asd = null;
|
||||||
|
//return asd;
|
||||||
|
return Pointer.Box(src.ToPointer(), _pointerType);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static object NativeToManagedByPass(TSource src) => src;
|
||||||
|
|
||||||
|
internal static object NativeToManaged(IntPtr src)
|
||||||
|
{
|
||||||
|
// typeof(TSource) != typeof(IntPtr)
|
||||||
|
TSource native = Marshal.PtrToStructure<TSource>(src);
|
||||||
|
return _nativeToManagedFunc(native);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static object NativeToManagedDirect(IntPtr src)
|
||||||
|
{
|
||||||
|
// typeof(TSource) != typeof(IntPtr)
|
||||||
|
TSource native = Unsafe.Read<TSource>(src.ToPointer());
|
||||||
|
return native;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static object MarshalToManaged2(IntPtr nativePtr, Type type)
|
||||||
|
{
|
||||||
|
static MarshalToManagedDelegate Factory(Type type)
|
||||||
|
{
|
||||||
|
Type marshalType = type;
|
||||||
|
if (marshalType.IsByRef)
|
||||||
|
marshalType = marshalType.GetElementType();
|
||||||
|
else if (marshalType.IsPointer)
|
||||||
|
marshalType = typeof(IntPtr);
|
||||||
|
|
||||||
|
MethodInfo method = typeof(MarshalHelper<>).MakeGenericType(marshalType).GetMethod(nameof(MarshalHelper<ReferenceTypePlaceholder>.ToManagedWrapper), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
return method.CreateDelegate<MarshalToManagedDelegate>();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type GetCustomMarshaller(Type type)
|
||||||
|
{
|
||||||
|
if (type == typeof(bool))
|
||||||
|
return typeof(BooleanMarshaller);
|
||||||
|
else if (type == typeof(string))
|
||||||
|
return typeof(StringMarshaller); // UTF-16 strings via MMethod::Invoke
|
||||||
|
else if (type == typeof(object))
|
||||||
|
return typeof(AsManagedHandleMarshaller);
|
||||||
|
else if (type.IsArray)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
Type marshallerType = type.GetCustomAttribute<NativeMarshallingAttribute>()?.NativeType;
|
||||||
|
//if (marshallerType == null && marshallerType != type)
|
||||||
|
// marshallerType = type.GetCustomAttribute<NativeMarshallingAttribute>()?.NativeType;
|
||||||
|
|
||||||
|
return marshallerType;
|
||||||
|
}
|
||||||
|
static (Type, Func<object, object>, Func<IntPtr, object>) Factory2(Type type)
|
||||||
|
{
|
||||||
|
Type marshalType = type;
|
||||||
|
if (marshalType.IsByRef)
|
||||||
|
marshalType = marshalType.GetElementType();
|
||||||
|
|
||||||
|
if (marshalType == typeof(byte*) || marshalType == typeof(char*))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (marshalType.IsPointer)
|
||||||
|
marshalType = typeof(IntPtr);
|
||||||
|
|
||||||
|
Type marshallerType = GetCustomMarshaller(marshalType);
|
||||||
|
if (marshalType.IsArray)
|
||||||
|
{
|
||||||
|
Type elementType = marshalType.GetElementType();
|
||||||
|
Type elementMarshallerType = GetCustomMarshaller(elementType);
|
||||||
|
if (elementMarshallerType == null)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MethodInfo method2 = elementMarshallerType.GetMethod("ConvertToManaged", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
var elementInternalType = method2.GetParameters()[0].ParameterType;
|
||||||
|
var types2 = new Type[] { elementType, elementInternalType };
|
||||||
|
marshallerType = typeof(NativeArrayMarshaller<,>).MakeGenericType(types2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (marshallerType == null)
|
||||||
|
{
|
||||||
|
if (marshalType == typeof(IntPtr))
|
||||||
|
{
|
||||||
|
//var setup = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
//setup.Invoke(null, [method]);
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedByPass), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
Func<object, object> func = (obj) => obj;
|
||||||
|
return (typeof(IntPtr), func, convdirectdel);
|
||||||
|
}
|
||||||
|
else if (marshalType == typeof(ManagedHandle))
|
||||||
|
{
|
||||||
|
var methody = typeof(ManagedHandle).GetMethod(nameof(ManagedHandle.FromIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var setup = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
setup.Invoke(null, [methody]);
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
Func<object, object> func = (obj) => ManagedHandle.FromIntPtr((IntPtr)obj);
|
||||||
|
return (typeof(IntPtr), func, convdirectdel);
|
||||||
|
}
|
||||||
|
else if (marshalType.IsPointer)
|
||||||
|
{
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(IntPtr), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
Func<object, object> func = (obj) => obj;
|
||||||
|
return (typeof(IntPtr), func, convdirectdel);
|
||||||
|
//return (null, null, null);
|
||||||
|
/*var setup = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType.GetElementType(), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
setup.Invoke(null, [null]);
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType.GetElementType(), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedPointer), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
return (marshalType, null, convdirectdel);*/
|
||||||
|
}
|
||||||
|
else if (marshalType.IsPrimitive || marshalType.IsEnum)
|
||||||
|
{
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType, marshalType]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
return (marshalType, null, convdirectdel);
|
||||||
|
}
|
||||||
|
else if (!marshalType.IsArray && IsBlittable(marshalType))
|
||||||
|
{
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([marshalType, marshalType]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedDirect), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
return (marshalType, null, convdirectdel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*else if (marshalType == typeof(object))
|
||||||
|
{
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType([typeof(ManagedHandle), typeof(IntPtr)]).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
Func<object, object> func = (obj) => (IntPtr)obj != IntPtr.Zero ? ManagedHandle.FromIntPtr((IntPtr)obj).Target : null;
|
||||||
|
return (typeof(IntPtr), func, null);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
if (marshallerType == null)
|
||||||
|
return (null, null, null);
|
||||||
|
|
||||||
|
MethodInfo method = marshallerType.GetMethod("ConvertToManaged", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
if (method == null)
|
||||||
|
{
|
||||||
|
// [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
|
||||||
|
// [CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
|
||||||
|
|
||||||
|
var customMarshallerAttributes = marshallerType.GetCustomAttributes<CustomMarshallerAttribute>();
|
||||||
|
foreach (var attrib in customMarshallerAttributes)
|
||||||
|
{
|
||||||
|
if (attrib.MarshalMode == MarshalMode.ManagedToUnmanagedOut)
|
||||||
|
{
|
||||||
|
var asdf = typeof(NativeArrayMarshaller<,>.NativeToManaged);
|
||||||
|
marshallerType = attrib.MarshallerType;
|
||||||
|
//method = marshallerType.GetMethod("ConvertToManaged", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
var internalType = method.GetParameters()[0].ParameterType;
|
||||||
|
var types = new Type[] { marshalType, internalType };
|
||||||
|
var convertDelegate = method.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(types));
|
||||||
|
|
||||||
|
var minit = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.Init), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
minit.Invoke(null, [method]);
|
||||||
|
var conv = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.NativeToManaged), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdel = conv.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
|
||||||
|
if (internalType == typeof(IntPtr))
|
||||||
|
{
|
||||||
|
var convdirect = typeof(NewMarshalHelper<,>).MakeGenericType(types).GetMethod(nameof(NewMarshalHelper<,>.NativeToManagedIntPtr), BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
||||||
|
var convdirectdel = convdirect.CreateDelegate<Func<IntPtr, object>>();
|
||||||
|
|
||||||
|
Func<object, object> func =
|
||||||
|
(obj) => convertDelegate.DynamicInvoke(obj);
|
||||||
|
|
||||||
|
return (internalType, func, convdirectdel);
|
||||||
|
}
|
||||||
|
else if (internalType.IsStructure())
|
||||||
|
{
|
||||||
|
Func<object, object> func =
|
||||||
|
(obj) => convertDelegate.DynamicInvoke(obj);
|
||||||
|
|
||||||
|
return (internalType, func, convdel);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Func<object, object> func =
|
||||||
|
(obj) => convertDelegate.DynamicInvoke(obj);
|
||||||
|
return (internalType, func, convdel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var type2 = type.IsByRef ? type.GetElementType() : type;
|
||||||
|
/*if (type2.IsPrimitive)
|
||||||
|
{
|
||||||
|
if (type.IsByRef && type2 == typeof(IntPtr))
|
||||||
|
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||||
|
|
||||||
|
//ref byte src = ref Unsafe.AsRef<byte>(nativePtr.ToPointer());
|
||||||
|
//var ret = RuntimeHelpers.Box(ref src, type.TypeHandle);
|
||||||
|
var ret = Marshal.PtrToStructure(nativePtr, type2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else if (type2.IsEnum)
|
||||||
|
{
|
||||||
|
if (type.IsByRef)
|
||||||
|
type2 = type2;
|
||||||
|
ref byte src = ref Unsafe.AsRef<byte>(nativePtr.ToPointer());
|
||||||
|
var ret = RuntimeHelpers.Box(ref src, type2.TypeHandle);
|
||||||
|
return ret;
|
||||||
|
}*/
|
||||||
|
if (!_marshallers.TryGetValue(type, out var marsh))
|
||||||
|
marsh = _marshallers.GetOrAdd(type, Factory2);
|
||||||
|
if (marsh.Item3 != null)
|
||||||
|
{
|
||||||
|
//object conv1 = deleg(nativePtr, type.IsByRef && false);
|
||||||
|
if (type.IsByRef && marsh.Item1 == typeof(IntPtr))
|
||||||
|
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||||
|
if (true && marsh.Item3 != null)
|
||||||
|
{
|
||||||
|
// TODO: CustomMarshaller.Free()
|
||||||
|
return marsh.Item3(nativePtr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
object value = marsh.Item1 == typeof(IntPtr) ? nativePtr : Marshal.PtrToStructure(nativePtr, marsh.Item1);
|
||||||
|
object conv2 = marsh.Item2(value);
|
||||||
|
|
||||||
|
// TODO: CustomMarshaller.Free()
|
||||||
|
return conv2;
|
||||||
|
}
|
||||||
|
/*if (conv1 is null && conv2 is null)
|
||||||
|
{ }
|
||||||
|
else if (!conv1.Equals(conv2))
|
||||||
|
Assert.IsTrue(conv1.Equals(conv2));*/
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
if (type2.IsStructure())
|
||||||
|
{
|
||||||
|
var ret = Marshal.PtrToStructure(nativePtr, type2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (type2 == typeof(int) || type2.IsEnum
|
||||||
|
|| type2 == typeof(IntPtr) || type2 == typeof(Float2) || type2 == typeof(Float3)
|
||||||
|
|| type2 == typeof(long) || type2 == typeof(sbyte)
|
||||||
|
|| type2 == typeof(uint) || type2 == typeof(ulong) || type2 == typeof(ushort) || type2 == typeof(byte)
|
||||||
|
|| type2 == typeof(float) || type2 == typeof(double))
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
else if (type2 == typeof(byte*) || type2 == typeof(Guid) || type2.IsArray)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!toManagedMarshallers.TryGetValue(type, out var deleg))
|
||||||
|
deleg = toManagedMarshallers.GetOrAdd(type, Factory);
|
||||||
|
return deleg(nativePtr, type.IsByRef && false);
|
||||||
|
}
|
||||||
|
|
||||||
internal static object MarshalToManaged(IntPtr nativePtr, Type type)
|
internal static object MarshalToManaged(IntPtr nativePtr, Type type)
|
||||||
{
|
{
|
||||||
static MarshalToManagedDelegate Factory(Type type)
|
static MarshalToManagedDelegate Factory(Type type)
|
||||||
@@ -369,7 +762,7 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
if (!toManagedMarshallers.TryGetValue(type, out var deleg))
|
if (!toManagedMarshallers.TryGetValue(type, out var deleg))
|
||||||
deleg = toManagedMarshallers.GetOrAdd(type, Factory);
|
deleg = toManagedMarshallers.GetOrAdd(type, Factory);
|
||||||
return deleg(nativePtr, type.IsByRef);
|
return deleg(nativePtr, type.IsByRef && false);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void MarshalToNative(object managedObject, IntPtr nativePtr, Type type)
|
internal static void MarshalToNative(object managedObject, IntPtr nativePtr, Type type)
|
||||||
@@ -495,6 +888,7 @@ namespace FlaxEngine.Interop
|
|||||||
internal static int[] marshallableFieldOffsets;
|
internal static int[] marshallableFieldOffsets;
|
||||||
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
|
internal static MarshalFieldTypedDelegate[] toManagedFieldMarshallers;
|
||||||
internal static MarshalFieldTypedDelegate[] toNativeFieldMarshallers;
|
internal static MarshalFieldTypedDelegate[] toNativeFieldMarshallers;
|
||||||
|
private static int marshalledSize;
|
||||||
|
|
||||||
private static MarshalToNativeTypedDelegate toNativeTypedMarshaller;
|
private static MarshalToNativeTypedDelegate toNativeTypedMarshaller;
|
||||||
private static MarshalToManagedTypedDelegate toManagedTypedMarshaller;
|
private static MarshalToManagedTypedDelegate toManagedTypedMarshaller;
|
||||||
@@ -525,7 +919,33 @@ namespace FlaxEngine.Interop
|
|||||||
MethodInfo toManagedFieldMethod;
|
MethodInfo toManagedFieldMethod;
|
||||||
MethodInfo toNativeFieldMethod;
|
MethodInfo toNativeFieldMethod;
|
||||||
|
|
||||||
if (fieldType.IsPointer)
|
if (fieldType == typeof(SoftTypeReference))
|
||||||
|
{
|
||||||
|
if (type.IsValueType)
|
||||||
|
{
|
||||||
|
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldSoftTypeReferenceValueType), bindingFlags);
|
||||||
|
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldSoftTypeReferenceValueType), bindingFlags);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldSoftTypeReferenceReferenceType), bindingFlags);
|
||||||
|
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldSoftTypeReferenceReferenceType), bindingFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldType == typeof(string))
|
||||||
|
{
|
||||||
|
if (type.IsValueType)
|
||||||
|
{
|
||||||
|
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldStringValueType), bindingFlags);
|
||||||
|
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldStringValueType), bindingFlags);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toManagedFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToManagedFieldStringReferenceType), bindingFlags);
|
||||||
|
toNativeFieldMethod = typeof(MarshalHelper<>).MakeGenericType(type).GetMethod(nameof(MarshalHelper<T>.ToNativeFieldStringReferenceType), bindingFlags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fieldType.IsPointer)
|
||||||
{
|
{
|
||||||
if (type.IsValueType)
|
if (type.IsValueType)
|
||||||
{
|
{
|
||||||
@@ -609,6 +1029,15 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*if (marshallableFieldOffsets != null)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < marshallableFieldOffsets.Length; i++)
|
||||||
|
{
|
||||||
|
if (marshallableFieldOffsets[i - 1] > marshallableFieldOffsets[i])
|
||||||
|
throw new NativeInteropException("marshal field offsets");
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
// Setup marshallers for managed and native directions
|
// Setup marshallers for managed and native directions
|
||||||
MethodInfo toManagedMethod;
|
MethodInfo toManagedMethod;
|
||||||
if (type.IsValueType)
|
if (type.IsValueType)
|
||||||
@@ -625,18 +1054,31 @@ namespace FlaxEngine.Interop
|
|||||||
//toManagedDelegate = toManagedMethod.CreateDelegate();//.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(type, toManagedMethod.GetParameters()[0].ParameterType));
|
//toManagedDelegate = toManagedMethod.CreateDelegate();//.CreateDelegate(typeof(ToManagedDelegate<,>).MakeGenericType(type, toManagedMethod.GetParameters()[0].ParameterType));
|
||||||
string methodName = nameof(MarshalInternalHelper<ValueTypePlaceholder, ValueTypePlaceholder>.ToManagedMarshaller);
|
string methodName = nameof(MarshalInternalHelper<ValueTypePlaceholder, ValueTypePlaceholder>.ToManagedMarshaller);
|
||||||
toManagedMethod = typeof(MarshalInternalHelper<,>).MakeGenericType(types).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
toManagedMethod = typeof(MarshalInternalHelper<,>).MakeGenericType(types).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
marshalledSize = RuntimeHelpers.SizeOf(internalType.TypeHandle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string methodName;
|
string methodName;
|
||||||
if (type == typeof(IntPtr))
|
if (type == typeof(IntPtr))
|
||||||
|
{
|
||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedPointer);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedPointer);
|
||||||
|
marshalledSize = Unsafe.SizeOf<IntPtr>();
|
||||||
|
}
|
||||||
else if (type == typeof(ManagedHandle))
|
else if (type == typeof(ManagedHandle))
|
||||||
|
{
|
||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedHandle);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedHandle);
|
||||||
|
marshalledSize = Unsafe.SizeOf<IntPtr>();
|
||||||
|
}
|
||||||
else if (marshallableFields != null)
|
else if (marshallableFields != null)
|
||||||
|
{
|
||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedWithMarshallableFields);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedWithMarshallableFields);
|
||||||
|
marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManaged);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManaged);
|
||||||
|
marshalledSize = RuntimeHelpers.SizeOf(type.TypeHandle);
|
||||||
|
}
|
||||||
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -650,10 +1092,14 @@ namespace FlaxEngine.Interop
|
|||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArray);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArray);
|
||||||
else
|
else
|
||||||
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArrayMarshalled);
|
methodName = nameof(MarshalHelperValueType<ValueTypePlaceholder>.ToManagedArrayMarshalled);
|
||||||
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(type.GetElementType()).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
toManagedMethod = typeof(MarshalHelperValueType<>).MakeGenericType(elementType).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
marshalledSize = RuntimeHelpers.SizeOf(elementType.TypeHandle);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type.GetElementType()).GetMethod(nameof(MarshalHelperReferenceType<ReferenceTypePlaceholder>.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
|
{
|
||||||
|
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(elementType).GetMethod(nameof(MarshalHelperReferenceType<ReferenceTypePlaceholder>.ToManagedArray), BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
marshalledSize = Unsafe.SizeOf<IntPtr>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -669,7 +1115,10 @@ namespace FlaxEngine.Interop
|
|||||||
else
|
else
|
||||||
throw new NativeInteropException($"Unsupported type '{type.FullName}'");
|
throw new NativeInteropException($"Unsupported type '{type.FullName}'");
|
||||||
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
toManagedMethod = typeof(MarshalHelperReferenceType<>).MakeGenericType(type).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
|
||||||
|
marshalledSize = Unsafe.SizeOf<IntPtr>();
|
||||||
}
|
}
|
||||||
|
if (marshalledSize <= 0)
|
||||||
|
throw new NativeInteropException($"Missing marshalled size for type '{type.FullName}'");
|
||||||
toManagedTypedMarshaller = toManagedMethod.CreateDelegate<MarshalToManagedTypedDelegate>();
|
toManagedTypedMarshaller = toManagedMethod.CreateDelegate<MarshalToManagedTypedDelegate>();
|
||||||
|
|
||||||
MethodInfo toNativeMethod;
|
MethodInfo toNativeMethod;
|
||||||
@@ -745,6 +1194,18 @@ namespace FlaxEngine.Interop
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static Array ToManagedArray2(NativeArrayTypeless nativeArray)
|
||||||
|
{
|
||||||
|
T[] arr = new T[nativeArray.Length];
|
||||||
|
IntPtr nativePtr = (IntPtr)nativeArray.Data;
|
||||||
|
for (int i = 0; i < arr.Length; i++)
|
||||||
|
{
|
||||||
|
toManagedTypedMarshaller(ref arr[i], nativePtr, false);
|
||||||
|
nativePtr += marshalledSize;
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
|
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
|
||||||
{
|
{
|
||||||
toNativeTypedMarshaller(ref managedValue, nativePtr);
|
toNativeTypedMarshaller(ref managedValue, nativePtr);
|
||||||
@@ -814,6 +1275,106 @@ namespace FlaxEngine.Interop
|
|||||||
fieldSize = IntPtr.Size;
|
fieldSize = IntPtr.Size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void ToManagedFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
|
||||||
|
string value = nativeValue.ToString();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
|
||||||
|
#else
|
||||||
|
ref string fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
|
||||||
|
fieldValueRef = value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToManagedFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
|
||||||
|
string value = nativeValue.ToString();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
|
||||||
|
#else
|
||||||
|
ref string fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
|
||||||
|
fieldValueRef = value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToNativeFieldStringValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
string fieldValue = field.GetValue(fieldOwner);
|
||||||
|
#else
|
||||||
|
string fieldValue = FieldHelper.GetValueTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
|
||||||
|
#endif
|
||||||
|
NativeString value = new NativeString(fieldValue);
|
||||||
|
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToNativeFieldStringReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
string fieldValue = field.GetValue(fieldOwner);
|
||||||
|
#else
|
||||||
|
string fieldValue = FieldHelper.GetReferenceTypeFieldReference<T, string>(fieldOffset, ref fieldOwner);
|
||||||
|
#endif
|
||||||
|
NativeString value = new NativeString(fieldValue);
|
||||||
|
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToManagedFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
|
||||||
|
SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
|
||||||
|
#else
|
||||||
|
ref SoftTypeReference fieldValueRef = ref FieldHelper.GetValueTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
|
||||||
|
fieldValueRef = value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToManagedFieldSoftTypeReferenceReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
NativeString nativeValue = Unsafe.Read<NativeString>(nativeFieldPtr.ToPointer());
|
||||||
|
SoftTypeReference value = new SoftTypeReference(nativeValue.ToString());
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
FieldHelper.SetReferenceTypeField(field, ref fieldOwner, value);
|
||||||
|
#else
|
||||||
|
ref SoftTypeReference fieldValueRef = ref FieldHelper.GetReferenceTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
|
||||||
|
fieldValueRef = value;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToNativeFieldSoftTypeReferenceValueType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : struct
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
SoftTypeReference fieldValue = field.GetValue(fieldOwner);
|
||||||
|
#else
|
||||||
|
SoftTypeReference fieldValue = FieldHelper.GetValueTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
|
||||||
|
#endif
|
||||||
|
NativeString value = new NativeString(fieldValue);
|
||||||
|
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ToNativeFieldSoftTypeReferenceReferenceType(FieldInfo field, int fieldOffset, ref T fieldOwner, IntPtr nativeFieldPtr, out int fieldSize) // where T : class
|
||||||
|
{
|
||||||
|
fieldSize = Unsafe.SizeOf<NativeString>();
|
||||||
|
#if USE_AOT || DOTNET_HOST_MONO
|
||||||
|
SoftTypeReference fieldValue = field.GetValue(fieldOwner);
|
||||||
|
#else
|
||||||
|
SoftTypeReference fieldValue = FieldHelper.GetReferenceTypeFieldReference<T, SoftTypeReference>(fieldOffset, ref fieldOwner);
|
||||||
|
#endif
|
||||||
|
NativeString value = new NativeString(fieldValue);
|
||||||
|
Unsafe.Write<NativeString>(nativeFieldPtr.ToPointer(), value);
|
||||||
|
}
|
||||||
|
|
||||||
private static IntPtr EnsureAlignment(IntPtr ptr, int alignment)
|
private static IntPtr EnsureAlignment(IntPtr ptr, int alignment)
|
||||||
{
|
{
|
||||||
if (ptr % alignment != 0)
|
if (ptr % alignment != 0)
|
||||||
@@ -1140,13 +1701,17 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef)
|
internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef)
|
||||||
{
|
{
|
||||||
if (byRef)
|
//if (byRef)
|
||||||
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
// nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||||
|
|
||||||
if (nativePtr != IntPtr.Zero)
|
if (nativePtr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
|
||||||
managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
|
IntPtr data = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||||
|
var span = new Span<T>(data.ToPointer(), length);
|
||||||
|
managedValue = span.ToArray();
|
||||||
|
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||||
|
//managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
managedValue = null;
|
managedValue = null;
|
||||||
@@ -1159,8 +1724,12 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
if (nativePtr != IntPtr.Zero)
|
if (nativePtr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
|
||||||
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray));
|
IntPtr data = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||||
|
NativeArrayTypeless array = new(data, length);
|
||||||
|
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray2(array)); // element size for internal structure needed here
|
||||||
|
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||||
|
//managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
managedValue = null;
|
managedValue = null;
|
||||||
@@ -1172,6 +1741,7 @@ namespace FlaxEngine.Interop
|
|||||||
var fields = MarshalHelper<T>.marshallableFields;
|
var fields = MarshalHelper<T>.marshallableFields;
|
||||||
var offsets = MarshalHelper<T>.marshallableFieldOffsets;
|
var offsets = MarshalHelper<T>.marshallableFieldOffsets;
|
||||||
var marshallers = MarshalHelper<T>.toNativeFieldMarshallers;
|
var marshallers = MarshalHelper<T>.toNativeFieldMarshallers;
|
||||||
|
|
||||||
for (int i = 0; i < fields.Length; i++)
|
for (int i = 0; i < fields.Length; i++)
|
||||||
{
|
{
|
||||||
marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize);
|
marshallers[i](fields[i], offsets[i], ref managedValue, nativePtr, out int fieldSize);
|
||||||
@@ -1235,8 +1805,9 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
if (nativePtr != IntPtr.Zero)
|
if (nativePtr != IntPtr.Zero)
|
||||||
{
|
{
|
||||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
NativeArray<IntPtr>* array = (NativeArray<IntPtr>*)nativePtr;
|
||||||
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(managedArray.ToSpan<IntPtr>()));
|
var span = array->AsSpan();
|
||||||
|
managedValue = Unsafe.As<T[]>(MarshalHelper<T>.ToManagedArray(span));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
managedValue = null;
|
managedValue = null;
|
||||||
@@ -1245,7 +1816,8 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static void ToNativeString(ref string managedValue, IntPtr nativePtr)
|
internal static void ToNativeString(ref string managedValue, IntPtr nativePtr)
|
||||||
{
|
{
|
||||||
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), ManagedString.ToNative/*Weak*/(managedValue));
|
//Unsafe.Write<IntPtr>(nativePtr.ToPointer(), ManagedString.ToNative/*Weak*/(managedValue));
|
||||||
|
Unsafe.Write<NativeString>(nativePtr.ToPointer(), new NativeString(managedValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ToNativeType(ref Type managedValue, IntPtr nativePtr)
|
internal static void ToNativeType(ref Type managedValue, IntPtr nativePtr)
|
||||||
@@ -1267,34 +1839,59 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static void ToNativeArray(ref T managedValue, IntPtr nativePtr)
|
internal static void ToNativeArray(ref T managedValue, IntPtr nativePtr)
|
||||||
{
|
{
|
||||||
IntPtr managedPtr;
|
IntPtr arrayDataPtr;
|
||||||
|
int arrayLength;
|
||||||
if (managedValue == null)
|
if (managedValue == null)
|
||||||
managedPtr = IntPtr.Zero;
|
{
|
||||||
|
arrayDataPtr = IntPtr.Zero;
|
||||||
|
arrayLength = 0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Type type = typeof(T);
|
Type type = typeof(T);
|
||||||
var elementType = type.GetElementType();
|
var elementType = type.GetElementType();
|
||||||
var arr = Unsafe.As<Array>(managedValue);
|
var arr = Unsafe.As<Array>(managedValue);
|
||||||
|
arrayLength = arr.Length;
|
||||||
var marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
var marshalledType = ArrayFactory.GetMarshalledType(elementType);
|
||||||
ManagedArray managedArray;
|
|
||||||
if (marshalledType == elementType)
|
if (marshalledType == elementType)
|
||||||
managedArray = ManagedArray.WrapNewArray(arr, type);
|
{
|
||||||
|
var elementLength = RuntimeHelpers.SizeOf(marshalledType.TypeHandle);
|
||||||
|
var bytesLength = elementLength * arrayLength;
|
||||||
|
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)bytesLength, 16);
|
||||||
|
arrayDataPtr = (IntPtr)ptr;
|
||||||
|
for (int i = 0; i < arr.Length; i++)
|
||||||
|
{
|
||||||
|
MarshalToNative(arr.GetValue(i), (IntPtr)ptr, elementType);
|
||||||
|
ptr += elementLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (elementType.IsValueType)
|
else if (elementType.IsValueType)
|
||||||
{
|
{
|
||||||
// Convert array of custom structures into internal native layout
|
// Convert array of custom structures into internal native layout
|
||||||
managedArray = ManagedArray.AllocateNewArray(arr.Length, type, marshalledType);
|
var elementLength = RuntimeHelpers.SizeOf(marshalledType.TypeHandle);
|
||||||
IntPtr managedArrayPtr = managedArray.Pointer;
|
var bytesLength = elementLength * arrayLength;
|
||||||
|
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)bytesLength, 16);
|
||||||
|
arrayDataPtr = (IntPtr)ptr;
|
||||||
for (int i = 0; i < arr.Length; i++)
|
for (int i = 0; i < arr.Length; i++)
|
||||||
{
|
{
|
||||||
MarshalToNative(arr.GetValue(i), managedArrayPtr, elementType);
|
MarshalToNative(arr.GetValue(i), (IntPtr)ptr, elementType);
|
||||||
managedArrayPtr += managedArray.ElementSize;
|
ptr += elementLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
managedArray = ManagedArrayToGCHandleWrappedArray(arr);
|
{
|
||||||
managedPtr = ManagedHandle.ToIntPtr(managedArray/*, GCHandleType.Weak*/);
|
byte* ptr = (byte*)NativeMemory.AlignedAlloc((UIntPtr)(Unsafe.SizeOf<IntPtr>() * arrayLength), 16);
|
||||||
|
arrayDataPtr = (IntPtr)ptr;
|
||||||
|
for (int i = 0; i < arr.Length; i++)
|
||||||
|
{
|
||||||
|
var obj = arr.GetValue(i);
|
||||||
|
Unsafe.Write<IntPtr>(ptr, obj != null ? ManagedHandle.ToIntPtr(obj) : IntPtr.Zero);
|
||||||
|
ptr += Unsafe.SizeOf<IntPtr>();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), managedPtr);
|
Unsafe.Write<IntPtr>(nativePtr.ToPointer(), arrayDataPtr);
|
||||||
|
Unsafe.Write<long>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer(), arrayLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
|
internal static void ToNative(ref T managedValue, IntPtr nativePtr)
|
||||||
@@ -1757,7 +2354,7 @@ namespace FlaxEngine.Interop
|
|||||||
|
|
||||||
internal static void InitMethods()
|
internal static void InitMethods()
|
||||||
{
|
{
|
||||||
return;
|
#if false
|
||||||
MakeNewCustomDelegateFunc =
|
MakeNewCustomDelegateFunc =
|
||||||
typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers")
|
typeof(Expression).Assembly.GetType("System.Linq.Expressions.Compiler.DelegateHelpers")
|
||||||
.GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate<Func<Type[], Type>>();
|
.GetMethod("MakeNewCustomDelegate", BindingFlags.NonPublic | BindingFlags.Static).CreateDelegate<Func<Type[], Type>>();
|
||||||
@@ -1789,6 +2386,7 @@ namespace FlaxEngine.Interop
|
|||||||
var ret = MakeNewCustomDelegateFuncCollectible(new[] { typeof(void) });
|
var ret = MakeNewCustomDelegateFuncCollectible(new[] { typeof(void) });
|
||||||
Assert.IsTrue(ret.IsCollectible);
|
Assert.IsTrue(ret.IsCollectible);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1809,7 +2407,7 @@ namespace FlaxEngine.Interop
|
|||||||
return MakeNewCustomDelegateFunc(parameters);
|
return MakeNewCustomDelegateFunc(parameters);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class ObjectArrayPool
|
internal static class ObjectArrayPool
|
||||||
{
|
{
|
||||||
@@ -1916,8 +2514,8 @@ namespace FlaxEngine.Interop
|
|||||||
internal MethodInfo method;
|
internal MethodInfo method;
|
||||||
internal MethodInvoker invoker;
|
internal MethodInvoker invoker;
|
||||||
internal Type[] parameterTypes;
|
internal Type[] parameterTypes;
|
||||||
internal Invoker.InvokeThunkDelegate methodDelegate;
|
//internal Invoker.InvokeThunkDelegate methodDelegate;
|
||||||
internal object methodDelegateContext;
|
//internal object methodDelegateContext;
|
||||||
|
|
||||||
internal static object[] objectPool = new object[128];
|
internal static object[] objectPool = new object[128];
|
||||||
internal static int objectPoolIndex = 0;
|
internal static int objectPoolIndex = 0;
|
||||||
@@ -2075,7 +2673,7 @@ namespace FlaxEngine.Interop
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class NativeInteropException : Exception
|
internal class NativeInteropException : Exception
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ void GPUContext::FrameBegin()
|
|||||||
|
|
||||||
void GPUContext::FrameEnd()
|
void GPUContext::FrameEnd()
|
||||||
{
|
{
|
||||||
ClearState();
|
ResetState();
|
||||||
FlushState();
|
FlushState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ public:
|
|||||||
/// [Deprecated in v1.10]
|
/// [Deprecated in v1.10]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns><c>true</c> if depth buffer is binded; otherwise, <c>false</c>.</returns>
|
/// <returns><c>true</c> if depth buffer is binded; otherwise, <c>false</c>.</returns>
|
||||||
DEPRECATED("IsDepthBufferBinded has been deprecated and will be removed in ")
|
DEPRECATED("IsDepthBufferBinded has been deprecated and will be removed in future")
|
||||||
virtual bool IsDepthBufferBinded() = 0;
|
virtual bool IsDepthBufferBinded() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -617,8 +617,17 @@ public:
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Clears the context state.
|
/// Clears the context state.
|
||||||
|
/// [Deprecated in v1.12]
|
||||||
/// </summary>
|
/// </summary>
|
||||||
API_FUNCTION() virtual void ClearState() = 0;
|
API_FUNCTION() DEPRECATED("Use ResetState instead") void ClearState()
|
||||||
|
{
|
||||||
|
ResetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the context state.
|
||||||
|
/// </summary>
|
||||||
|
API_FUNCTION() virtual void ResetState() = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flushes the internal cached context state with a command buffer.
|
/// Flushes the internal cached context state with a command buffer.
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ bool DeferredMaterialShader::Load()
|
|||||||
psDesc.DepthWriteEnable = true;
|
psDesc.DepthWriteEnable = true;
|
||||||
psDesc.DepthEnable = true;
|
psDesc.DepthEnable = true;
|
||||||
psDesc.DepthFunc = ComparisonFunc::Less;
|
psDesc.DepthFunc = ComparisonFunc::Less;
|
||||||
|
psDesc.BlendMode.RenderTargetWriteMask = BlendingMode::ColorWrite::None;
|
||||||
psDesc.HS = nullptr;
|
psDesc.HS = nullptr;
|
||||||
psDesc.DS = nullptr;
|
psDesc.DS = nullptr;
|
||||||
GPUShaderProgramVS* instancedDepthPassVS;
|
GPUShaderProgramVS* instancedDepthPassVS;
|
||||||
|
|||||||
@@ -195,5 +195,10 @@ bool ForwardMaterialShader::Load()
|
|||||||
psDesc.VS = _shader->GetVS("VS_Skinned");
|
psDesc.VS = _shader->GetVS("VS_Skinned");
|
||||||
_cache.DepthSkinned.Init(psDesc);
|
_cache.DepthSkinned.Init(psDesc);
|
||||||
|
|
||||||
|
#if PLATFORM_PS5
|
||||||
|
// Fix shader binding issues on forward shading materials on PS5
|
||||||
|
_drawModes = DrawPass::None;
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -264,5 +264,10 @@ bool ParticleMaterialShader::Load()
|
|||||||
// Lazy initialization
|
// Lazy initialization
|
||||||
_cacheVolumetricFog.Desc.PS = nullptr;
|
_cacheVolumetricFog.Desc.PS = nullptr;
|
||||||
|
|
||||||
|
#if PLATFORM_PS5
|
||||||
|
// Fix shader binding issues on forward shading materials on PS5
|
||||||
|
_drawModes = DrawPass::None;
|
||||||
|
#endif
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -113,7 +113,8 @@ GPUTexture* RenderBuffers::RequestHalfResDepth(GPUContext* context)
|
|||||||
|
|
||||||
PixelFormat RenderBuffers::GetOutputFormat() const
|
PixelFormat RenderBuffers::GetOutputFormat() const
|
||||||
{
|
{
|
||||||
return _useAlpha ? PixelFormat::R16G16B16A16_Float : PixelFormat::R11G11B10_Float;
|
// TODO: fix incorrect alpha leaking into reflections on PS5 with R11G11B10_Float
|
||||||
|
return _useAlpha || PLATFORM_PS5 ? PixelFormat::R16G16B16A16_Float : PixelFormat::R11G11B10_Float;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RenderBuffers::GetUseAlpha() const
|
bool RenderBuffers::GetUseAlpha() const
|
||||||
|
|||||||
@@ -216,20 +216,21 @@ GPUVertexLayout* GPUVertexLayout::Get(const Span<GPUVertexLayout*>& layouts)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing, int32 missingSlotOverride)
|
GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused, bool addMissing, int32 missingSlotOverride, bool referenceOrder)
|
||||||
{
|
{
|
||||||
GPUVertexLayout* result = base ? base : reference;
|
GPUVertexLayout* result = base ? base : reference;
|
||||||
if (base && reference && base != reference)
|
if (base && reference && base != reference)
|
||||||
{
|
{
|
||||||
bool elementsModified = false;
|
bool elementsModified = false;
|
||||||
Elements newElements = base->GetElements();
|
Elements newElements = base->GetElements();
|
||||||
|
const Elements& refElements = reference->GetElements();
|
||||||
if (removeUnused)
|
if (removeUnused)
|
||||||
{
|
{
|
||||||
for (int32 i = newElements.Count() - 1; i >= 0; i--)
|
for (int32 i = newElements.Count() - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
bool missing = true;
|
bool missing = true;
|
||||||
const VertexElement& e = newElements.Get()[i];
|
const VertexElement& e = newElements.Get()[i];
|
||||||
for (const VertexElement& ee : reference->GetElements())
|
for (const VertexElement& ee : refElements)
|
||||||
{
|
{
|
||||||
if (ee.Type == e.Type)
|
if (ee.Type == e.Type)
|
||||||
{
|
{
|
||||||
@@ -247,7 +248,7 @@ GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout*
|
|||||||
}
|
}
|
||||||
if (addMissing)
|
if (addMissing)
|
||||||
{
|
{
|
||||||
for (const VertexElement& e : reference->GetElements())
|
for (const VertexElement& e : refElements)
|
||||||
{
|
{
|
||||||
bool missing = true;
|
bool missing = true;
|
||||||
for (const VertexElement& ee : base->GetElements())
|
for (const VertexElement& ee : base->GetElements())
|
||||||
@@ -282,6 +283,32 @@ GPUVertexLayout* GPUVertexLayout::Merge(GPUVertexLayout* base, GPUVertexLayout*
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (referenceOrder)
|
||||||
|
{
|
||||||
|
for (int32 i = 0, j = 0; i < newElements.Count() && j < refElements.Count(); j++)
|
||||||
|
{
|
||||||
|
if (newElements[i].Type == refElements[j].Type)
|
||||||
|
{
|
||||||
|
// Elements match so move forward
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find reference element in a new list
|
||||||
|
for (int32 k = i + 1; k < newElements.Count(); k++)
|
||||||
|
{
|
||||||
|
if (newElements[k].Type == refElements[j].Type)
|
||||||
|
{
|
||||||
|
// Move matching element to the reference position
|
||||||
|
VertexElement e = newElements[k];
|
||||||
|
newElements.RemoveAt(k);
|
||||||
|
newElements.Insert(i, e);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (elementsModified)
|
if (elementsModified)
|
||||||
result = Get(newElements, true);
|
result = Get(newElements, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,8 +84,9 @@ public:
|
|||||||
/// <param name="removeUnused">True to remove elements from base layout that don't exist in a reference layout.</param>
|
/// <param name="removeUnused">True to remove elements from base layout that don't exist in a reference layout.</param>
|
||||||
/// <param name="addMissing">True to add missing elements to base layout that exist in a reference layout.</param>
|
/// <param name="addMissing">True to add missing elements to base layout that exist in a reference layout.</param>
|
||||||
/// <param name="missingSlotOverride">Allows to override the input slot for missing elements. Use value -1 to inherit slot from the reference layout.</param>
|
/// <param name="missingSlotOverride">Allows to override the input slot for missing elements. Use value -1 to inherit slot from the reference layout.</param>
|
||||||
|
/// <param name="referenceOrder">True to reorder result elements to match the reference layout. For example, if input vertex buffer layout is different than vertex shader then it can match those.</param>
|
||||||
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
/// <returns>Vertex layout object. Doesn't need to be cleared as it's cached for an application lifetime.</returns>
|
||||||
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true, int32 missingSlotOverride = -1);
|
static GPUVertexLayout* Merge(GPUVertexLayout* base, GPUVertexLayout* reference, bool removeUnused = false, bool addMissing = true, int32 missingSlotOverride = -1, bool referenceOrder = false);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// [GPUResource]
|
// [GPUResource]
|
||||||
|
|||||||
@@ -724,7 +724,7 @@ void GPUContextDX11::SetState(GPUPipelineState* state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUContextDX11::ClearState()
|
void GPUContextDX11::ResetState()
|
||||||
{
|
{
|
||||||
if (!_context)
|
if (!_context)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ public:
|
|||||||
void SetScissor(const Rectangle& scissorRect) override;
|
void SetScissor(const Rectangle& scissorRect) override;
|
||||||
GPUPipelineState* GetState() const override;
|
GPUPipelineState* GetState() const override;
|
||||||
void SetState(GPUPipelineState* state) override;
|
void SetState(GPUPipelineState* state) override;
|
||||||
void ClearState() override;
|
void ResetState() override;
|
||||||
void FlushState() override;
|
void FlushState() override;
|
||||||
void Flush() override;
|
void Flush() override;
|
||||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||||
|
|||||||
@@ -553,7 +553,7 @@ void GPUTextureDX11::initHandles()
|
|||||||
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
|
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
|
||||||
{
|
{
|
||||||
PixelFormat stencilFormat;
|
PixelFormat stencilFormat;
|
||||||
switch (_dxgiFormatDSV)
|
switch (static_cast<PixelFormat>(_dxgiFormatDSV))
|
||||||
{
|
{
|
||||||
case PixelFormat::D24_UNorm_S8_UInt:
|
case PixelFormat::D24_UNorm_S8_UInt:
|
||||||
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
|
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ void CommandQueueDX12::WaitForFence(uint64 fenceValue)
|
|||||||
|
|
||||||
void CommandQueueDX12::WaitForGPU()
|
void CommandQueueDX12::WaitForGPU()
|
||||||
{
|
{
|
||||||
|
PROFILE_CPU();
|
||||||
|
ZoneColor(TracyWaitZoneColor);
|
||||||
const uint64 value = _fence.Signal(this);
|
const uint64 value = _fence.Signal(this);
|
||||||
_fence.WaitCPU(value);
|
_fence.WaitCPU(value);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ bool GPUBufferDX12::OnInit()
|
|||||||
// Create resource
|
// Create resource
|
||||||
ID3D12Resource* resource;
|
ID3D12Resource* resource;
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS
|
||||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_CREATE_NOT_ZEROED;
|
D3D12_HEAP_FLAGS heapFlags = EnumHasAnyFlags(_desc.Flags, GPUBufferFlags::VertexBuffer | GPUBufferFlags::IndexBuffer) || _desc.InitData ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
|
||||||
#else
|
#else
|
||||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1304,7 +1304,7 @@ void GPUContextDX12::SetState(GPUPipelineState* state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUContextDX12::ClearState()
|
void GPUContextDX12::ResetState()
|
||||||
{
|
{
|
||||||
if (!_commandList)
|
if (!_commandList)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ public:
|
|||||||
void SetScissor(const Rectangle& scissorRect) override;
|
void SetScissor(const Rectangle& scissorRect) override;
|
||||||
GPUPipelineState* GetState() const override;
|
GPUPipelineState* GetState() const override;
|
||||||
void SetState(GPUPipelineState* state) override;
|
void SetState(GPUPipelineState* state) override;
|
||||||
void ClearState() override;
|
void ResetState() override;
|
||||||
void FlushState() override;
|
void FlushState() override;
|
||||||
void Flush() override;
|
void Flush() override;
|
||||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||||
|
|||||||
@@ -628,6 +628,7 @@ bool GPUDeviceDX12::Init()
|
|||||||
VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));
|
VALIDATE_DIRECTX_CALL(dxgiAdapter->EnumOutputs(0, dxgiOutput.GetAddressOf()));
|
||||||
DXGI_FORMAT backbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT);
|
DXGI_FORMAT backbufferFormat = RenderToolsDX::ToDxgiFormat(GPU_BACK_BUFFER_PIXEL_FORMAT);
|
||||||
UINT modesCount = 0;
|
UINT modesCount = 0;
|
||||||
|
#ifdef _GAMING_XBOX_SCARLETT
|
||||||
VALIDATE_DIRECTX_CALL(dxgiOutput->GetDisplayModeList(backbufferFormat, 0, &modesCount, NULL));
|
VALIDATE_DIRECTX_CALL(dxgiOutput->GetDisplayModeList(backbufferFormat, 0, &modesCount, NULL));
|
||||||
Array<DXGIXBOX_MODE_DESC> modes;
|
Array<DXGIXBOX_MODE_DESC> modes;
|
||||||
modes.Resize((int32)modesCount);
|
modes.Resize((int32)modesCount);
|
||||||
@@ -642,6 +643,11 @@ bool GPUDeviceDX12::Init()
|
|||||||
videoOutput.RefreshRate = Math::Max(videoOutput.RefreshRate, mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator);
|
videoOutput.RefreshRate = Math::Max(videoOutput.RefreshRate, mode.RefreshRate.Numerator / (float)mode.RefreshRate.Denominator);
|
||||||
}
|
}
|
||||||
modes.Resize(0);
|
modes.Resize(0);
|
||||||
|
#else
|
||||||
|
videoOutput.Width = 1920;
|
||||||
|
videoOutput.Height = 1080;
|
||||||
|
videoOutput.RefreshRate = 60;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if PLATFORM_GDK
|
#if PLATFORM_GDK
|
||||||
GDKPlatform::Suspended.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnSuspended>(this);
|
GDKPlatform::Suspended.Bind<GPUDeviceDX12, &GPUDeviceDX12::OnSuspended>(this);
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ public:
|
|||||||
/// <param name="device">The graphics device.</param>
|
/// <param name="device">The graphics device.</param>
|
||||||
/// <param name="name">The resource name.</param>
|
/// <param name="name">The resource name.</param>
|
||||||
GPUResourceDX12(GPUDeviceDX12* device, const StringView& name)
|
GPUResourceDX12(GPUDeviceDX12* device, const StringView& name)
|
||||||
: GPUResourceBase(device, name)
|
: GPUResourceBase<GPUDeviceDX12, BaseType>(device, name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ bool GPUTextureDX12::OnInit()
|
|||||||
initialState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
initialState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE | D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE;
|
||||||
|
|
||||||
// Create texture
|
// Create texture
|
||||||
#if PLATFORM_WINDOWS
|
#if PLATFORM_WINDOWS && 0
|
||||||
D3D12_HEAP_FLAGS heapFlags = useRTV || useDSV ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
|
D3D12_HEAP_FLAGS heapFlags = useRTV || useDSV ? D3D12_HEAP_FLAG_CREATE_NOT_ZEROED : D3D12_HEAP_FLAG_NONE;
|
||||||
#else
|
#else
|
||||||
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
D3D12_HEAP_FLAGS heapFlags = D3D12_HEAP_FLAG_NONE;
|
||||||
@@ -732,7 +732,7 @@ void GPUTextureDX12::initHandles()
|
|||||||
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
|
if (useDSV && useSRV && PixelFormatExtensions::HasStencil(format))
|
||||||
{
|
{
|
||||||
PixelFormat stencilFormat;
|
PixelFormat stencilFormat;
|
||||||
switch (_dxgiFormatDSV)
|
switch (static_cast<PixelFormat>(_dxgiFormatDSV))
|
||||||
{
|
{
|
||||||
case PixelFormat::D24_UNorm_S8_UInt:
|
case PixelFormat::D24_UNorm_S8_UInt:
|
||||||
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
|
srDesc.Format = DXGI_FORMAT_X24_TYPELESS_G8_UINT;
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearState() override
|
void ResetState() override
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1329,7 +1329,7 @@ void GPUContextVulkan::SetState(GPUPipelineState* state)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPUContextVulkan::ClearState()
|
void GPUContextVulkan::ResetState()
|
||||||
{
|
{
|
||||||
ResetRenderTarget();
|
ResetRenderTarget();
|
||||||
ResetSR();
|
ResetSR();
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ public:
|
|||||||
void SetScissor(const Rectangle& scissorRect) override;
|
void SetScissor(const Rectangle& scissorRect) override;
|
||||||
GPUPipelineState* GetState() const override;
|
GPUPipelineState* GetState() const override;
|
||||||
void SetState(GPUPipelineState* state) override;
|
void SetState(GPUPipelineState* state) override;
|
||||||
void ClearState() override;
|
void ResetState() override;
|
||||||
void FlushState() override;
|
void FlushState() override;
|
||||||
void Flush() override;
|
void Flush() override;
|
||||||
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
void UpdateBuffer(GPUBuffer* buffer, const void* data, uint32 size, uint32 offset) override;
|
||||||
|
|||||||
@@ -554,10 +554,11 @@ void AnimatedModel::StopSlotAnimation(const StringView& slotName, Animation* ani
|
|||||||
{
|
{
|
||||||
for (auto& slot : GraphInstance.Slots)
|
for (auto& slot : GraphInstance.Slots)
|
||||||
{
|
{
|
||||||
if (slot.Animation == anim && slot.Name == slotName)
|
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName)
|
||||||
{
|
{
|
||||||
//slot.Animation = nullptr; // TODO: make an immediate version of this method and set the animation to nullptr.
|
//slot.Animation = nullptr; // TODO: make an immediate version of this method and set the animation to nullptr.
|
||||||
slot.Reset = true;
|
if (slot.Animation != nullptr)
|
||||||
|
slot.Reset = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,7 +574,7 @@ void AnimatedModel::PauseSlotAnimation(const StringView& slotName, Animation* an
|
|||||||
{
|
{
|
||||||
for (auto& slot : GraphInstance.Slots)
|
for (auto& slot : GraphInstance.Slots)
|
||||||
{
|
{
|
||||||
if (slot.Animation == anim && slot.Name == slotName)
|
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName)
|
||||||
{
|
{
|
||||||
slot.Pause = true;
|
slot.Pause = true;
|
||||||
break;
|
break;
|
||||||
@@ -595,7 +596,7 @@ bool AnimatedModel::IsPlayingSlotAnimation(const StringView& slotName, Animation
|
|||||||
{
|
{
|
||||||
for (auto& slot : GraphInstance.Slots)
|
for (auto& slot : GraphInstance.Slots)
|
||||||
{
|
{
|
||||||
if (slot.Animation == anim && slot.Name == slotName && !slot.Pause)
|
if ((slot.Animation == anim || anim == nullptr) && slot.Name == slotName && !slot.Pause)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -412,8 +412,8 @@ public:
|
|||||||
/// Stops the animation playback on the slot in Anim Graph.
|
/// Stops the animation playback on the slot in Anim Graph.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slotName">The name of the slot.</param>
|
/// <param name="slotName">The name of the slot.</param>
|
||||||
/// <param name="anim">The animation to stop.</param>
|
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||||
API_FUNCTION() void StopSlotAnimation(const StringView& slotName, Animation* anim);
|
API_FUNCTION() void StopSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pauses all the animations playback on the all slots in Anim Graph.
|
/// Pauses all the animations playback on the all slots in Anim Graph.
|
||||||
@@ -424,8 +424,8 @@ public:
|
|||||||
/// Pauses the animation playback on the slot in Anim Graph.
|
/// Pauses the animation playback on the slot in Anim Graph.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slotName">The name of the slot.</param>
|
/// <param name="slotName">The name of the slot.</param>
|
||||||
/// <param name="anim">The animation to pause.</param>
|
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||||
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim);
|
API_FUNCTION() void PauseSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if any animation playback is active on any slot in Anim Graph (not paused).
|
/// Checks if any animation playback is active on any slot in Anim Graph (not paused).
|
||||||
@@ -436,8 +436,8 @@ public:
|
|||||||
/// Checks if the animation playback is active on the slot in Anim Graph (not paused).
|
/// Checks if the animation playback is active on the slot in Anim Graph (not paused).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="slotName">The name of the slot.</param>
|
/// <param name="slotName">The name of the slot.</param>
|
||||||
/// <param name="anim">The animation to check.</param>
|
/// <param name="anim">The animation to check. Null to use slot name only.</param>
|
||||||
API_FUNCTION() bool IsPlayingSlotAnimation(const StringView& slotName, Animation* anim);
|
API_FUNCTION() bool IsPlayingSlotAnimation(const StringView& slotName, Animation* anim = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ApplyRootMotion(const Transform& rootMotionDelta);
|
void ApplyRootMotion(const Transform& rootMotionDelta);
|
||||||
|
|||||||
@@ -1123,6 +1123,32 @@ SceneResult SceneLoader::OnBegin(Args& args)
|
|||||||
_lastSceneLoadTime = DateTime::Now();
|
_lastSceneLoadTime = DateTime::Now();
|
||||||
StartFrame = Engine::UpdateCount;
|
StartFrame = Engine::UpdateCount;
|
||||||
|
|
||||||
|
// Validate arguments
|
||||||
|
if (!args.Data.IsArray())
|
||||||
|
{
|
||||||
|
LOG(Error, "Invalid Data member.");
|
||||||
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, Guid::Empty);
|
||||||
|
return SceneResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek scene node value (it's the first actor serialized)
|
||||||
|
SceneId = JsonTools::GetGuid(args.Data[0], "ID");
|
||||||
|
if (!SceneId.IsValid())
|
||||||
|
{
|
||||||
|
LOG(Error, "Invalid scene id.");
|
||||||
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
||||||
|
return SceneResult::Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Peek meta
|
||||||
|
if (args.EngineBuild < 6000)
|
||||||
|
{
|
||||||
|
LOG(Error, "Invalid serialized engine build.");
|
||||||
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
||||||
|
return SceneResult::Failed;
|
||||||
|
}
|
||||||
|
Modifier->EngineBuild = args.EngineBuild;
|
||||||
|
|
||||||
// Scripting backend should be loaded for the current project before loading scene
|
// Scripting backend should be loaded for the current project before loading scene
|
||||||
if (!Scripting::HasGameModulesLoaded())
|
if (!Scripting::HasGameModulesLoaded())
|
||||||
{
|
{
|
||||||
@@ -1136,27 +1162,7 @@ SceneResult SceneLoader::OnBegin(Args& args)
|
|||||||
MessageBox::Show(TEXT("Failed to load scripts.\n\nCannot load scene without game script modules.\n\nSee logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
MessageBox::Show(TEXT("Failed to load scripts.\n\nCannot load scene without game script modules.\n\nSee logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return SceneResult::Failed;
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
||||||
}
|
|
||||||
|
|
||||||
// Peek meta
|
|
||||||
if (args.EngineBuild < 6000)
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid serialized engine build.");
|
|
||||||
return SceneResult::Failed;
|
|
||||||
}
|
|
||||||
if (!args.Data.IsArray())
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid Data member.");
|
|
||||||
return SceneResult::Failed;
|
|
||||||
}
|
|
||||||
Modifier->EngineBuild = args.EngineBuild;
|
|
||||||
|
|
||||||
// Peek scene node value (it's the first actor serialized)
|
|
||||||
SceneId = JsonTools::GetGuid(args.Data[0], "ID");
|
|
||||||
if (!SceneId.IsValid())
|
|
||||||
{
|
|
||||||
LOG(Error, "Invalid scene id.");
|
|
||||||
return SceneResult::Failed;
|
return SceneResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1164,6 +1170,7 @@ SceneResult SceneLoader::OnBegin(Args& args)
|
|||||||
if (Level::FindScene(SceneId) != nullptr)
|
if (Level::FindScene(SceneId) != nullptr)
|
||||||
{
|
{
|
||||||
LOG(Info, "Scene {0} is already loaded.", SceneId);
|
LOG(Info, "Scene {0} is already loaded.", SceneId);
|
||||||
|
CallSceneEvent(SceneEventType::OnSceneLoadError, nullptr, SceneId);
|
||||||
return SceneResult::Failed;
|
return SceneResult::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,7 +194,8 @@ CultureInfo MUtils::ToNative(void* value)
|
|||||||
if (lcidProperty && lcidProperty->GetGetMethod())
|
if (lcidProperty && lcidProperty->GetGetMethod())
|
||||||
{
|
{
|
||||||
MObject* lcidObj = lcidProperty->GetGetMethod()->Invoke(value, nullptr, nullptr);
|
MObject* lcidObj = lcidProperty->GetGetMethod()->Invoke(value, nullptr, nullptr);
|
||||||
lcid = *(int32*)MCore::Object::Unbox(lcidObj);
|
PLATFORM_DEBUG_BREAK;
|
||||||
|
MCore::Object::Unbox(lcidObj, &lcid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const Char* GetCommandLine(int argc, char* argv[])
|
|||||||
const Char* cmdLine;
|
const Char* cmdLine;
|
||||||
if (length != 0)
|
if (length != 0)
|
||||||
{
|
{
|
||||||
Char* str = (Char*)malloc(length * sizeof(Char));
|
Char* str = (Char*)malloc((length + 1) * sizeof(Char));
|
||||||
cmdLine = str;
|
cmdLine = str;
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -100,6 +100,35 @@ API_STRUCT(NoDefault, Namespace="FlaxEngine.Networking") struct FLAXENGINE_API N
|
|||||||
return Word0 + Word1 != 0;
|
return Word0 + Word1 != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NetworkClientsMask operator&(const NetworkClientsMask& other) const
|
||||||
|
{
|
||||||
|
return { Word0 & other.Word0, Word1 & other.Word1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkClientsMask operator|(const NetworkClientsMask& other) const
|
||||||
|
{
|
||||||
|
return { Word0 | other.Word0, Word1 | other.Word1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkClientsMask operator~() const
|
||||||
|
{
|
||||||
|
return { ~Word0, ~Word1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkClientsMask& operator|=(const NetworkClientsMask& other)
|
||||||
|
{
|
||||||
|
Word0 |= other.Word0;
|
||||||
|
Word1 |= other.Word1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkClientsMask& operator&=(const NetworkClientsMask& other)
|
||||||
|
{
|
||||||
|
Word0 &= other.Word0;
|
||||||
|
Word1 &= other.Word1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const NetworkClientsMask& other) const
|
bool operator==(const NetworkClientsMask& other) const
|
||||||
{
|
{
|
||||||
return Word0 == other.Word0 && Word1 == other.Word1;
|
return Word0 == other.Word0 && Word1 == other.Word1;
|
||||||
|
|||||||
@@ -116,17 +116,6 @@ PACK_STRUCT(struct NetworkMessageObjectRpc
|
|||||||
|
|
||||||
struct NetworkReplicatedObject
|
struct NetworkReplicatedObject
|
||||||
{
|
{
|
||||||
ScriptingObjectReference<ScriptingObject> Object;
|
|
||||||
Guid ObjectId;
|
|
||||||
Guid ParentId;
|
|
||||||
uint32 OwnerClientId;
|
|
||||||
uint32 LastOwnerFrame = 0;
|
|
||||||
NetworkObjectRole Role;
|
|
||||||
uint8 Spawned : 1;
|
|
||||||
uint8 Synced : 1;
|
|
||||||
DataContainer<uint32> TargetClientIds;
|
|
||||||
INetworkObject* AsNetworkObject;
|
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
NetworkClientsMask Mask;
|
NetworkClientsMask Mask;
|
||||||
@@ -139,6 +128,17 @@ struct NetworkReplicatedObject
|
|||||||
}
|
}
|
||||||
} RepCache;
|
} RepCache;
|
||||||
|
|
||||||
|
ScriptingObjectReference<ScriptingObject> Object;
|
||||||
|
Guid ObjectId;
|
||||||
|
Guid ParentId;
|
||||||
|
DataContainer<uint32> TargetClientIds;
|
||||||
|
INetworkObject* AsNetworkObject;
|
||||||
|
uint32 OwnerClientId;
|
||||||
|
uint32 LastOwnerFrame = 0;
|
||||||
|
NetworkObjectRole Role;
|
||||||
|
uint8 Spawned : 1;
|
||||||
|
uint8 Synced : 1;
|
||||||
|
|
||||||
NetworkReplicatedObject()
|
NetworkReplicatedObject()
|
||||||
{
|
{
|
||||||
Spawned = 0;
|
Spawned = 0;
|
||||||
@@ -152,12 +152,12 @@ struct NetworkReplicatedObject
|
|||||||
|
|
||||||
bool operator==(const NetworkReplicatedObject& other) const
|
bool operator==(const NetworkReplicatedObject& other) const
|
||||||
{
|
{
|
||||||
return Object == other.Object;
|
return ObjectId == other.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const ScriptingObject* other) const
|
bool operator==(const ScriptingObject* other) const
|
||||||
{
|
{
|
||||||
return Object == other;
|
return other && ObjectId == other->GetID();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(const Guid& other) const
|
bool operator==(const Guid& other) const
|
||||||
@@ -176,6 +176,11 @@ inline uint32 GetHash(const NetworkReplicatedObject& key)
|
|||||||
return GetHash(key.ObjectId);
|
return GetHash(key.ObjectId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline uint32 GetHash(const ScriptingObject* key)
|
||||||
|
{
|
||||||
|
return key ? GetHash(key->GetID()) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct Serializer
|
struct Serializer
|
||||||
{
|
{
|
||||||
NetworkReplicator::SerializeFunc Methods[2];
|
NetworkReplicator::SerializeFunc Methods[2];
|
||||||
@@ -698,14 +703,11 @@ void SendReplication(ScriptingObject* obj, NetworkClientsMask targetClients)
|
|||||||
return;
|
return;
|
||||||
auto& item = it->Item;
|
auto& item = it->Item;
|
||||||
const bool isClient = NetworkManager::IsClient();
|
const bool isClient = NetworkManager::IsClient();
|
||||||
|
const NetworkClientsMask fullTargetClients = targetClients;
|
||||||
|
|
||||||
// Skip serialization of objects that none will receive
|
// If server has no recipients, skip early.
|
||||||
if (!isClient)
|
if (!isClient && !targetClients)
|
||||||
{
|
return;
|
||||||
BuildCachedTargets(item, targetClients);
|
|
||||||
if (CachedTargets.Count() == 0)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.AsNetworkObject)
|
if (item.AsNetworkObject)
|
||||||
item.AsNetworkObject->OnNetworkSerialize();
|
item.AsNetworkObject->OnNetworkSerialize();
|
||||||
@@ -728,18 +730,30 @@ void SendReplication(ScriptingObject* obj, NetworkClientsMask targetClients)
|
|||||||
|
|
||||||
#if USE_NETWORK_REPLICATOR_CACHE
|
#if USE_NETWORK_REPLICATOR_CACHE
|
||||||
// Process replication cache to skip sending object data if it didn't change
|
// Process replication cache to skip sending object data if it didn't change
|
||||||
if (item.RepCache.Data.Length() == size &&
|
if (item.RepCache.Data.Length() == size && Platform::MemoryCompare(item.RepCache.Data.Get(), stream->GetBuffer(), size) == 0)
|
||||||
item.RepCache.Mask == targetClients &&
|
|
||||||
Platform::MemoryCompare(item.RepCache.Data.Get(), stream->GetBuffer(), size) == 0)
|
|
||||||
{
|
{
|
||||||
return;
|
// Check if only newly joined clients are missing this data to avoid resending it to everyone
|
||||||
|
NetworkClientsMask missingClients = targetClients & ~item.RepCache.Mask;
|
||||||
|
|
||||||
|
// If data is the same and only the client set changed, replicate to missing clients only
|
||||||
|
if (!missingClients)
|
||||||
|
return;
|
||||||
|
targetClients = missingClients;
|
||||||
}
|
}
|
||||||
item.RepCache.Mask = targetClients;
|
item.RepCache.Mask = fullTargetClients;
|
||||||
item.RepCache.Data.Copy(stream->GetBuffer(), size);
|
item.RepCache.Data.Copy(stream->GetBuffer(), size);
|
||||||
#endif
|
#endif
|
||||||
// TODO: use Unreliable for dynamic objects that are replicated every frame? (eg. player state)
|
// TODO: use Unreliable for dynamic objects that are replicated every frame? (eg. player state)
|
||||||
constexpr NetworkChannelType repChannel = NetworkChannelType::Reliable;
|
constexpr NetworkChannelType repChannel = NetworkChannelType::Reliable;
|
||||||
|
|
||||||
|
// Skip serialization of objects that none will receive
|
||||||
|
if (!isClient)
|
||||||
|
{
|
||||||
|
BuildCachedTargets(item, targetClients);
|
||||||
|
if (CachedTargets.Count() == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Send object to clients
|
// Send object to clients
|
||||||
NetworkMessageObjectReplicate msgData;
|
NetworkMessageObjectReplicate msgData;
|
||||||
msgData.OwnerFrame = NetworkManager::Frame;
|
msgData.OwnerFrame = NetworkManager::Frame;
|
||||||
@@ -1530,7 +1544,21 @@ void NetworkReplicator::DespawnObject(ScriptingObject* obj)
|
|||||||
// Register for despawning (batched during update)
|
// Register for despawning (batched during update)
|
||||||
auto& despawn = DespawnQueue.AddOne();
|
auto& despawn = DespawnQueue.AddOne();
|
||||||
despawn.Id = obj->GetID();
|
despawn.Id = obj->GetID();
|
||||||
despawn.Targets = item.TargetClientIds;
|
if (item.TargetClientIds.IsValid())
|
||||||
|
{
|
||||||
|
despawn.Targets = item.TargetClientIds;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Snapshot current recipients to avoid sending despawn to clients that connect later (and never got the spawn)
|
||||||
|
Array<uint32, InlinedAllocation<8>> clientIds;
|
||||||
|
for (const NetworkClient* client : NetworkManager::Clients)
|
||||||
|
{
|
||||||
|
if (client->State == NetworkConnectionState::Connected && client->ClientId != item.OwnerClientId)
|
||||||
|
clientIds.Add(client->ClientId);
|
||||||
|
}
|
||||||
|
despawn.Targets.Copy(clientIds);
|
||||||
|
}
|
||||||
|
|
||||||
// Prevent spawning
|
// Prevent spawning
|
||||||
for (int32 i = 0; i < SpawnQueue.Count(); i++)
|
for (int32 i = 0; i < SpawnQueue.Count(); i++)
|
||||||
@@ -1823,6 +1851,31 @@ void NetworkInternal::NetworkReplicatorClientConnected(NetworkClient* client)
|
|||||||
{
|
{
|
||||||
ScopeLock lock(ObjectsLock);
|
ScopeLock lock(ObjectsLock);
|
||||||
NewClients.Add(client);
|
NewClients.Add(client);
|
||||||
|
|
||||||
|
// Ensure cached replication acknowledges the new client without resending to others.
|
||||||
|
// Clear the new client's bit in RepCache and schedule a near-term replication.
|
||||||
|
const int32 clientIndex = NetworkManager::Clients.Find(client);
|
||||||
|
if (clientIndex != -1)
|
||||||
|
{
|
||||||
|
const uint64 bitMask = 1ull << (uint64)(clientIndex % 64);
|
||||||
|
const int32 wordIndex = clientIndex / 64;
|
||||||
|
for (auto it = Objects.Begin(); it.IsNotEnd(); ++it)
|
||||||
|
{
|
||||||
|
auto& item = it->Item;
|
||||||
|
ScriptingObject* obj = item.Object.Get();
|
||||||
|
if (!obj || !item.Spawned || item.Role != NetworkObjectRole::OwnedAuthoritative)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Mark this client as missing cached data
|
||||||
|
uint64* word = wordIndex == 0 ? &item.RepCache.Mask.Word0 : &item.RepCache.Mask.Word1;
|
||||||
|
*word &= ~bitMask;
|
||||||
|
|
||||||
|
// Force next replication tick for this object so the new client gets data promptly
|
||||||
|
if (Hierarchy)
|
||||||
|
Hierarchy->DirtyObject(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ASSERT(sizeof(NetworkClientsMask) * 8 >= (uint32)NetworkManager::Clients.Count()); // Ensure that clients mask can hold all of clients
|
ASSERT(sizeof(NetworkClientsMask) * 8 >= (uint32)NetworkManager::Clients.Count()); // Ensure that clients mask can hold all of clients
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2275,7 +2328,9 @@ void NetworkInternal::OnNetworkMessageObjectDespawn(NetworkEvent& event, Network
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NETWORK_REPLICATOR_LOG(Error, "[NetworkReplicator] Failed to despawn object {}", objectId);
|
// If this client never had the object (eg. it was targeted to other clients only), drop the message quietly
|
||||||
|
DespawnedObjects.Add(objectId);
|
||||||
|
NETWORK_REPLICATOR_LOG(Warning, "[NetworkReplicator] Failed to despawn object {}", objectId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -482,9 +482,15 @@ void ParticleEmitterGraphCPUExecutor::ProcessGroupFunction(Box* box, Node* node,
|
|||||||
// Function Input
|
// Function Input
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
|
// Skip when graph is too small (eg. preview) and fallback with default value from the function graph
|
||||||
|
if (context.GraphStack.Count() < 2)
|
||||||
|
{
|
||||||
|
value = tryGetValue(node->TryGetBox(1), Value::Zero);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Find the function call
|
// Find the function call
|
||||||
Node* functionCallNode = nullptr;
|
Node* functionCallNode = nullptr;
|
||||||
ASSERT(context.GraphStack.Count() >= 2);
|
|
||||||
ParticleEmitterGraphCPU* graph;
|
ParticleEmitterGraphCPU* graph;
|
||||||
for (int32 i = context.CallStackSize - 1; i >= 0; i--)
|
for (int32 i = context.CallStackSize - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -83,17 +83,19 @@ void AppleFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& res
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case SpecialFolder::Desktop:
|
case SpecialFolder::Desktop:
|
||||||
result = home / TEXT("/Desktop");
|
result = home / TEXT("/Desktop"); // TODO: should be NSDesktopDirectory
|
||||||
break;
|
break;
|
||||||
case SpecialFolder::Documents:
|
case SpecialFolder::Documents:
|
||||||
result = home / TEXT("/Documents");
|
result = home / TEXT("/Documents"); // TODO: should be NSDocumentDirectory
|
||||||
break;
|
break;
|
||||||
case SpecialFolder::Pictures:
|
case SpecialFolder::Pictures:
|
||||||
result = home / TEXT("/Pictures");
|
result = home / TEXT("/Pictures"); // TODO: should be NSPicturesDirectory
|
||||||
break;
|
break;
|
||||||
case SpecialFolder::AppData:
|
case SpecialFolder::AppData:
|
||||||
|
result = home / TEXT("/Library/Application Support"); // TODO: should be NSApplicationSupportDirectory
|
||||||
|
break;
|
||||||
case SpecialFolder::LocalAppData:
|
case SpecialFolder::LocalAppData:
|
||||||
result = home / TEXT("/Library/Caches");
|
result = home / TEXT("/Library/Caches"); // TODO: should be NSApplicationSupportDirectory
|
||||||
break;
|
break;
|
||||||
case SpecialFolder::ProgramData:
|
case SpecialFolder::ProgramData:
|
||||||
result = home / TEXT("/Library/Application Support");
|
result = home / TEXT("/Library/Application Support");
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ Array<User*, FixedAllocation<8>> PlatformBase::Users;
|
|||||||
Delegate<User*> PlatformBase::UserAdded;
|
Delegate<User*> PlatformBase::UserAdded;
|
||||||
Delegate<User*> PlatformBase::UserRemoved;
|
Delegate<User*> PlatformBase::UserRemoved;
|
||||||
void* OutOfMemoryBuffer = nullptr;
|
void* OutOfMemoryBuffer = nullptr;
|
||||||
|
volatile int64 FatalReporting = 0;
|
||||||
|
|
||||||
const Char* ToString(NetworkConnectionType value)
|
const Char* ToString(NetworkConnectionType value)
|
||||||
{
|
{
|
||||||
@@ -330,11 +331,20 @@ int32 PlatformBase::GetCacheLineSize()
|
|||||||
|
|
||||||
void PlatformBase::Fatal(const StringView& msg, void* context, FatalErrorType error)
|
void PlatformBase::Fatal(const StringView& msg, void* context, FatalErrorType error)
|
||||||
{
|
{
|
||||||
|
// Let only one thread to report the error (and wait for it to end to have valid log before crash)
|
||||||
|
RETRY:
|
||||||
|
if (Platform::InterlockedCompareExchange(&FatalReporting, 1, 0) != 0)
|
||||||
|
{
|
||||||
|
Platform::Sleep(1);
|
||||||
|
goto RETRY;
|
||||||
|
}
|
||||||
|
|
||||||
// Check if is already during fatal state
|
// Check if is already during fatal state
|
||||||
if (Engine::FatalError != FatalErrorType::None)
|
if (Engine::FatalError != FatalErrorType::None)
|
||||||
{
|
{
|
||||||
// Just send one more error to the log and back
|
// Just send one more error to the log and back
|
||||||
LOG(Error, "Error after fatal error: {0}", msg);
|
LOG(Error, "Error after fatal error: {0}", msg);
|
||||||
|
Platform::AtomicStore(&FatalReporting, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -453,6 +463,8 @@ void PlatformBase::Fatal(const StringView& msg, void* context, FatalErrorType er
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Platform::AtomicStore(&FatalReporting, 0);
|
||||||
|
|
||||||
// Show error message
|
// Show error message
|
||||||
if (Engine::ReportCrash.IsBinded())
|
if (Engine::ReportCrash.IsBinded())
|
||||||
Engine::ReportCrash(msg, context);
|
Engine::ReportCrash(msg, context);
|
||||||
|
|||||||
@@ -338,17 +338,35 @@ void LinuxFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& res
|
|||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case SpecialFolder::Desktop:
|
case SpecialFolder::Desktop:
|
||||||
result = home / TEXT("Desktop");
|
{
|
||||||
|
String desktopDir;
|
||||||
|
if (!Platform::GetEnvironmentVariable(TEXT("XDG_DESKTOP_DIR"), desktopDir))
|
||||||
|
result = desktopDir;
|
||||||
|
else
|
||||||
|
result = home / TEXT("Desktop");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SpecialFolder::Documents:
|
case SpecialFolder::Documents:
|
||||||
result = String::Empty;
|
result = String::Empty;
|
||||||
break;
|
break;
|
||||||
case SpecialFolder::Pictures:
|
case SpecialFolder::Pictures:
|
||||||
result = home / TEXT("Pictures");
|
{
|
||||||
|
String picturesDir;
|
||||||
|
if (!Platform::GetEnvironmentVariable(TEXT("XDG_PICTURES_DIR"), picturesDir))
|
||||||
|
result = picturesDir;
|
||||||
|
else
|
||||||
|
result = home / TEXT("Pictures");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SpecialFolder::AppData:
|
case SpecialFolder::AppData:
|
||||||
result = TEXT("/usr/share");
|
{
|
||||||
|
String configHome;
|
||||||
|
if (!Platform::GetEnvironmentVariable(TEXT("XDG_CONFIG_HOME"), configHome))
|
||||||
|
result = configHome;
|
||||||
|
else
|
||||||
|
result = home / TEXT(".config");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case SpecialFolder::LocalAppData:
|
case SpecialFolder::LocalAppData:
|
||||||
{
|
{
|
||||||
String dataHome;
|
String dataHome;
|
||||||
|
|||||||
@@ -2993,6 +2993,7 @@ bool LinuxPlatform::SetEnvironmentVariable(const String& name, const String& val
|
|||||||
return setenv(StringAsANSI<>(*name).Get(), StringAsANSI<>(*value).Get(), true) != 0;
|
return setenv(StringAsANSI<>(*name).Get(), StringAsANSI<>(*value).Get(), true) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !PLATFORM_SDL
|
||||||
int32 LinuxPlatform::CreateProcess(CreateProcessSettings& settings)
|
int32 LinuxPlatform::CreateProcess(CreateProcessSettings& settings)
|
||||||
{
|
{
|
||||||
LOG(Info, "Command: {0} {1}", settings.FileName, settings.Arguments);
|
LOG(Info, "Command: {0} {1}", settings.FileName, settings.Arguments);
|
||||||
@@ -3106,6 +3107,7 @@ int32 LinuxPlatform::CreateProcess(CreateProcessSettings& settings)
|
|||||||
|
|
||||||
return returnCode;
|
return returnCode;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void* LinuxPlatform::LoadLibrary(const Char* filename)
|
void* LinuxPlatform::LoadLibrary(const Char* filename)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -148,7 +148,9 @@ public:
|
|||||||
static void GetEnvironmentVariables(Dictionary<String, String, HeapAllocation>& result);
|
static void GetEnvironmentVariables(Dictionary<String, String, HeapAllocation>& result);
|
||||||
static bool GetEnvironmentVariable(const String& name, String& value);
|
static bool GetEnvironmentVariable(const String& name, String& value);
|
||||||
static bool SetEnvironmentVariable(const String& name, const String& value);
|
static bool SetEnvironmentVariable(const String& name, const String& value);
|
||||||
|
#if !PLATFORM_SDL
|
||||||
static int32 CreateProcess(CreateProcessSettings& settings);
|
static int32 CreateProcess(CreateProcessSettings& settings);
|
||||||
|
#endif
|
||||||
static void* LoadLibrary(const Char* filename);
|
static void* LoadLibrary(const Char* filename);
|
||||||
static void FreeLibrary(void* handle);
|
static void FreeLibrary(void* handle);
|
||||||
static void* GetProcAddress(void* handle, const char* symbol);
|
static void* GetProcAddress(void* handle, const char* symbol);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user