_prog
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
Some checks failed
Build Android / Game (Android, Release ARM64) (push) Has been cancelled
Build iOS / Game (iOS, Release ARM64) (push) Has been cancelled
Build Linux / Editor (Linux, Development x64) (push) Has been cancelled
Build Linux / Game (Linux, Release x64) (push) Has been cancelled
Build macOS / Editor (Mac, Development ARM64) (push) Has been cancelled
Build macOS / Game (Mac, Release ARM64) (push) Has been cancelled
Build Windows / Editor (Windows, Development x64) (push) Has been cancelled
Build Windows / Game (Windows, Release x64) (push) Has been cancelled
Cooker / Cook (Mac) (push) Has been cancelled
Tests / Tests (Linux) (push) Has been cancelled
Tests / Tests (Windows) (push) Has been cancelled
This commit is contained in:
@@ -889,6 +889,11 @@ Variant::Variant(const Span<byte>& v)
|
||||
}
|
||||
}
|
||||
|
||||
Variant::Variant(const BytesContainer& v)
|
||||
: Variant((const Span<byte>&)(v))
|
||||
{
|
||||
}
|
||||
|
||||
PRAGMA_DISABLE_DEPRECATION_WARNINGS
|
||||
#include "Engine/Content/Deprecated.h"
|
||||
Variant::Variant(const CommonValue& value)
|
||||
|
||||
@@ -11,6 +11,9 @@ struct CommonValue;
|
||||
template<typename T>
|
||||
class AssetReference;
|
||||
struct ScriptingTypeHandle;
|
||||
template<typename T>
|
||||
class DataContainer;
|
||||
typedef DataContainer<byte> BytesContainer;
|
||||
|
||||
/// <summary>
|
||||
/// 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(const Dictionary<Variant, Variant, HeapAllocation>& v);
|
||||
explicit Variant(const Span<byte>& v);
|
||||
explicit Variant(const BytesContainer& v);
|
||||
explicit Variant(const CommonValue& v);
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#define USE_GCHANDLE
|
||||
//#define TRACK_HANDLES
|
||||
|
||||
|
||||
#if USE_NETCORE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#if USE_NETCORE
|
||||
using FlaxEngine.Assertions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@@ -322,27 +323,24 @@ namespace FlaxEngine.Interop
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public struct ManagedToNative
|
||||
public static class ManagedToNative
|
||||
{
|
||||
ManagedHandle handle;
|
||||
|
||||
public void FromManaged(object[] managed)
|
||||
public static object[] ConvertToManaged(NativeArray<IntPtr> unmanaged)
|
||||
{
|
||||
if (managed != null)
|
||||
{
|
||||
var managedArray = NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
|
||||
handle = ManagedHandle.Alloc(managedArray, GCHandleType.Weak);
|
||||
}
|
||||
if (unmanaged.Data == null)
|
||||
return null;
|
||||
return NativeInterop.GCHandleArrayToManagedArray<object>(unmanaged);
|
||||
}
|
||||
|
||||
public IntPtr ToUnmanaged()
|
||||
public static NativeArray<IntPtr> ConvertToUnmanaged(object[] managed)
|
||||
{
|
||||
return ManagedHandle.ToIntPtr(handle);
|
||||
if (managed == null)
|
||||
return new NativeArray<IntPtr>();
|
||||
return NativeInterop.ManagedArrayToGCHandleWrappedArray(managed);
|
||||
}
|
||||
|
||||
public void Free()
|
||||
public static void Free(NativeArray<IntPtr> unmanaged)
|
||||
{
|
||||
handle.Free();
|
||||
if (unmanaged.Data != null)
|
||||
unmanaged.Free();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -661,6 +659,431 @@ namespace FlaxEngine.Interop
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(BoxedArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(BoxedArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(BoxedArrayMarshaller<,>.Bidirectional))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(BoxedArrayMarshaller<,>))]
|
||||
[ContiguousCollectionMarshaller]
|
||||
public static unsafe class BoxedArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
|
||||
{
|
||||
if (managed == null)
|
||||
{
|
||||
numElements = 0;
|
||||
return new NativeArray<TUnmanagedElement>();
|
||||
}
|
||||
numElements = managed.Length;
|
||||
return new NativeArray<TUnmanagedElement>(managed.Length);
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
|
||||
{
|
||||
if (managed == null)
|
||||
return null;
|
||||
return managed.AsSpan();
|
||||
}
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return null;
|
||||
return unmanaged.AsSpan();
|
||||
}
|
||||
|
||||
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
|
||||
{
|
||||
if (unmanaged.Data != null)
|
||||
unmanaged.Free();
|
||||
}
|
||||
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return null;
|
||||
Assert.IsTrue(unmanaged.Length == numElements);
|
||||
return new T[unmanaged.Length];
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return null;
|
||||
return unmanaged.AsReadOnlySpan();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
if (managed == null)
|
||||
return null;
|
||||
return managed.AsSpan();
|
||||
}
|
||||
|
||||
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return;
|
||||
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
|
||||
}
|
||||
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public struct Bidirectional
|
||||
{
|
||||
//string managed;
|
||||
//IntPtr unmanaged;
|
||||
|
||||
public void FromManaged(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public T[] ToManaged()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public NativeArray<TUnmanagedElement> ToUnmanaged()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public unsafe /*ref*/ struct NativeArray<T> where T : unmanaged
|
||||
{
|
||||
public T* Data;
|
||||
public int Length;
|
||||
|
||||
public NativeArray(T* data, int length)
|
||||
{
|
||||
Data = data;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public NativeArray(Span<T> data)
|
||||
{
|
||||
Data = (T*)Marshal.AllocCoTaskMem(data.Length);
|
||||
Length = data.Length;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
Unsafe.Copy(&Data[i], ref data[i]);
|
||||
}
|
||||
|
||||
public NativeArray(IntPtr data, int length)
|
||||
{
|
||||
Data = (T*)data;
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public NativeArray(int length)
|
||||
{
|
||||
Data = (T*)Marshal.AllocCoTaskMem(length);
|
||||
Length = length;
|
||||
}
|
||||
|
||||
public NativeArray()
|
||||
{
|
||||
Data = null;
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
public void Free() => Marshal.FreeCoTaskMem((IntPtr)Data);
|
||||
|
||||
public Span<T> AsSpan() => new Span<T>(Data, Length);
|
||||
public ReadOnlySpan<T> AsReadOnlySpan() => new Span<T>(Data, Length);
|
||||
|
||||
public static bool operator ==(NativeArray<T> left, NativeArray<T> right) => left.Data == right.Data && left.Length == right.Length;
|
||||
public static bool operator !=(NativeArray<T> left, NativeArray<T> right) => left.Data != right.Data || left.Length != right.Length;
|
||||
public static bool operator ==(NativeArray<T> left, IntPtr right) => left.Data == (T*)right;
|
||||
public static bool operator !=(NativeArray<T> left, IntPtr right) => left.Data != (T*)right;
|
||||
public static bool operator ==(IntPtr left, NativeArray<T> right) => (T*)left == right.Data;
|
||||
public static bool operator !=(IntPtr left, NativeArray<T> right) => (T*)left != right.Data;
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is null) return false;
|
||||
if (obj is NativeArray<T> arr) return this == arr;
|
||||
if (obj is IntPtr ptr) return this == ptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode() => ((IntPtr)Data).GetHashCode() * 397 ^ Length.GetHashCode();
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedOut, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementIn, typeof(NativeArrayMarshaller<,>.ManagedToNative))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedIn, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementOut, typeof(NativeArrayMarshaller<,>.NativeToManaged))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ManagedToUnmanagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.UnmanagedToManagedRef, typeof(NativeArrayMarshaller<,>.Bidirectional))]
|
||||
[CustomMarshaller(typeof(CustomMarshallerAttribute.GenericPlaceholder[]), MarshalMode.ElementRef, typeof(NativeArrayMarshaller<,>))]
|
||||
[ContiguousCollectionMarshaller]
|
||||
public static unsafe class NativeArrayMarshaller<T, TUnmanagedElement> where TUnmanagedElement : unmanaged
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public static class ManagedToNative
|
||||
{
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
|
||||
|
||||
public static void Free(NativeArray<TUnmanagedElement> unmanaged) => throw new NotImplementedException();
|
||||
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public static class NativeToManaged
|
||||
{
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return Array.Empty<T>();
|
||||
Assert.IsTrue(unmanaged.Length == numElements);
|
||||
return new T[unmanaged.Length];
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return null;
|
||||
return unmanaged.AsReadOnlySpan();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
if (managed == null)
|
||||
return null;
|
||||
return managed.AsSpan();
|
||||
}
|
||||
|
||||
public static void Free(NativeArray<TUnmanagedElement> unmanaged)
|
||||
{
|
||||
if (unmanaged.Data == null)
|
||||
return;
|
||||
Marshal.FreeCoTaskMem((IntPtr)unmanaged.Data);
|
||||
}
|
||||
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements) => throw new NotImplementedException();
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed) => throw new NotImplementedException();
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
public struct Bidirectional
|
||||
{
|
||||
//string managed;
|
||||
//IntPtr unmanaged;
|
||||
|
||||
public void FromManaged(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public T[] ToManaged()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TUnmanagedElement> GetManagedValuesSource()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Span<TUnmanagedElement> GetUnmanagedValuesDestination()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Span<TUnmanagedElement> GetManagedValuesDestination(int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public NativeArray<TUnmanagedElement> ToUnmanaged()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void FromUnmanaged(NativeArray<TUnmanagedElement> unmanaged)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public static NativeArray<TUnmanagedElement> AllocateContainerForUnmanagedElements(T[] managed, out int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static T[] AllocateContainerForManagedElements(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<T> GetManagedValuesSource(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<TUnmanagedElement> GetUnmanagedValuesDestination(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<TUnmanagedElement> GetUnmanagedValuesSource(NativeArray<TUnmanagedElement> unmanaged, int numElements)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public static Span<T> GetManagedValuesDestination(T[] managed)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
[HideInEditor]
|
||||
#endif
|
||||
|
||||
@@ -188,6 +188,28 @@ namespace FlaxEngine.Interop
|
||||
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>
|
||||
/// Converts array of GC Handles from native runtime to managed array.
|
||||
/// </summary>
|
||||
@@ -238,6 +260,24 @@ namespace FlaxEngine.Interop
|
||||
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>
|
||||
/// Converts array with a custom converter function for each element.
|
||||
/// </summary>
|
||||
@@ -270,6 +310,23 @@ namespace FlaxEngine.Interop
|
||||
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>
|
||||
/// <param name="assemblyName">The name to find</param>
|
||||
/// <param name="allowPartial">If true, partial names should be allowed to be resolved.</param>
|
||||
@@ -1140,13 +1197,18 @@ namespace FlaxEngine.Interop
|
||||
|
||||
internal static void ToManagedArray(ref T[] managedValue, IntPtr nativePtr, bool byRef)
|
||||
{
|
||||
if (byRef)
|
||||
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||
//if (byRef)
|
||||
// nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||
|
||||
if (nativePtr != IntPtr.Zero)
|
||||
{
|
||||
ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||
managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
|
||||
int length = Unsafe.Read<int>(IntPtr.Add(nativePtr, Unsafe.SizeOf<IntPtr>()).ToPointer());
|
||||
nativePtr = Unsafe.Read<IntPtr>(nativePtr.ToPointer());
|
||||
|
||||
var span = new Span<T>(nativePtr.ToPointer(), length);
|
||||
managedValue = span.ToArray();
|
||||
//ManagedArray managedArray = Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(nativePtr).Target);
|
||||
//managedValue = Unsafe.As<T[]>(managedArray.ToArray<T>());
|
||||
}
|
||||
else
|
||||
managedValue = null;
|
||||
|
||||
@@ -68,13 +68,13 @@ public:
|
||||
struct FLAXENGINE_API Object
|
||||
{
|
||||
static MObject* Box(void* value, const MClass* klass);
|
||||
static void* Unbox(MObject* obj);
|
||||
static void Unbox(MObject* obj, void* dest);
|
||||
static void* Unbox(const MObject* obj);
|
||||
static void Unbox(const MObject* obj, void* dest);
|
||||
static MObject* New(const MClass* klass);
|
||||
static void Init(MObject* obj);
|
||||
static MClass* GetClass(MObject* obj);
|
||||
static MString* ToString(MObject* obj);
|
||||
static int32 GetHashCode(MObject* obj);
|
||||
static void Init(const MObject* obj);
|
||||
static MClass* GetClass(const MObject* obj);
|
||||
static MString* ToString(const MObject* obj);
|
||||
static int32 GetHashCode(const MObject* obj);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -82,11 +82,11 @@ public:
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API String
|
||||
{
|
||||
static MString* GetEmpty(MDomain* domain = nullptr);
|
||||
static MString* New(const char* str, int32 length, MDomain* domain = nullptr);
|
||||
static MString* New(const Char* str, int32 length, MDomain* domain = nullptr);
|
||||
static void Free(MString* obj);
|
||||
static StringView GetChars(MString* obj);
|
||||
static MString* GetEmpty(const MDomain* domain = nullptr);
|
||||
static MString* New(const char* str, int32 length, const MDomain* domain = nullptr);
|
||||
static MString* New(const Char* str, int32 length, const MDomain* domain = nullptr);
|
||||
static void Free(const MString* obj);
|
||||
static StringView GetChars(const MString* obj);
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -96,11 +96,11 @@ public:
|
||||
{
|
||||
static MArray* New(const MClass* elementKlass, int32 length);
|
||||
static void Free(const MArray* array);
|
||||
static MClass* GetClass(MClass* elementKlass);
|
||||
static MClass* GetClass(const MClass* elementKlass);
|
||||
static MClass* GetArrayClass(const MArray* obj);
|
||||
static int32 GetLength(const MArray* obj);
|
||||
static void* GetAddress(const MArray* obj);
|
||||
static MArray* Unbox(MObject* obj);
|
||||
static MArray* Unbox(const MObject* obj);
|
||||
|
||||
template<typename T>
|
||||
FORCE_INLINE static T* GetAddress(const MArray* obj)
|
||||
@@ -114,8 +114,8 @@ public:
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API GCHandle
|
||||
{
|
||||
static MGCHandle New(MObject* obj, bool pinned = false);
|
||||
static MGCHandle NewWeak(MObject* obj, bool trackResurrection = false);
|
||||
static MGCHandle New(const MObject* obj, bool pinned = false);
|
||||
static MGCHandle NewWeak(const MObject* obj, bool trackResurrection = false);
|
||||
static MObject* GetTarget(const MGCHandle& handle);
|
||||
static void Free(const MGCHandle& handle);
|
||||
};
|
||||
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
/// </remarks>
|
||||
/// <param name="instance">The object of given type to get value from.</param>
|
||||
/// <param name="result">The return value of undefined type.</param>
|
||||
void GetValue(MObject* instance, void* result) const;
|
||||
void GetValue(const MObject* instance, void* result) const;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null.
|
||||
@@ -116,14 +116,14 @@ public:
|
||||
/// </remarks>
|
||||
/// <param name="instance">The object of given type to get value from.</param>
|
||||
/// <param name="result">The return value of undefined type.</param>
|
||||
void GetValueReference(MObject* instance, void* result) const;
|
||||
void GetValueReference(const MObject* instance, void* result) const;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves value currently set in the field on the specified object instance. If field is static object instance can be null. If returned value is a value type it will be boxed.
|
||||
/// </summary>
|
||||
/// <param name="instance">The object of given type to get value from.</param>
|
||||
/// <returns>The boxed value object.</returns>
|
||||
MObject* GetValueBoxed(MObject* instance) const;
|
||||
MObject* GetValueBoxed(const MObject* instance) const;
|
||||
|
||||
/// <summary>
|
||||
/// Sets a value for the field on the specified object instance. If field is static object instance can be null.
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
/// </remarks>
|
||||
/// <param name="instance">The object of given type to set value to.</param>
|
||||
/// <param name="value">Th value of undefined type.</param>
|
||||
void SetValue(MObject* instance, void* value) const;
|
||||
void SetValue(const MObject* instance, void* value) const;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
|
||||
#if USE_CSHARP
|
||||
|
||||
/*static_assert(TIsPODType<int>::Value, "int not pod type?");
|
||||
static_assert(TIsPODType<Float3>::Value, "Float3 not pod type?");
|
||||
static_assert(!TIsPODType<ScriptingObject>::Value, "ScriptingObject not pod type?");
|
||||
static_assert(TIsPODType<Char>::Value, "Char not pod type?");
|
||||
static_assert(TIsPODType<char>::Value, "char not pod type?");*/
|
||||
|
||||
struct Version;
|
||||
class CultureInfo;
|
||||
template<typename AllocationType>
|
||||
@@ -49,6 +55,12 @@ struct MConverter
|
||||
{
|
||||
MObject* Box(const T& data, const MClass* klass);
|
||||
void Unbox(T& result, MObject* data);
|
||||
/*template<typename U>
|
||||
void ToManaged(U& result, const T& data);
|
||||
template<typename U>
|
||||
void ToNative(T& result, const U& data);
|
||||
void ToManaged(MObject*& result, const T& data);
|
||||
void ToNative(T& result, const MObject*& data);*/
|
||||
void FreeManaged(MObject* data);
|
||||
void ToManagedArray(MArray* result, const Span<T>& data);
|
||||
void ToNativeArray(Span<T>& result, const MArray* data);
|
||||
@@ -61,6 +73,16 @@ struct NativeArray
|
||||
{
|
||||
T* data;
|
||||
int32 length;
|
||||
|
||||
FORCE_INLINE operator T*() const
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
FORCE_INLINE Span<T> ToSpan() const
|
||||
{
|
||||
return Span<T>(data, length);
|
||||
}
|
||||
};
|
||||
|
||||
#if USE_NETCORE
|
||||
@@ -79,6 +101,16 @@ struct MConverter<bool>
|
||||
MCore::Object::Unbox(data, &result);
|
||||
}
|
||||
|
||||
void ToManaged(bool& result, const bool& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(bool& result, const bool& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void FreeManaged(MObject* data)
|
||||
{
|
||||
}
|
||||
@@ -116,6 +148,16 @@ struct MConverter<T, typename TEnableIf<TAnd<TIsPODType<T>, TNot<TIsBaseOf<class
|
||||
MCore::Object::Unbox(data, &result);
|
||||
}
|
||||
|
||||
void ToManaged(T& result, const T& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(T& result, const T& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<T>& data)
|
||||
{
|
||||
Platform::MemoryCopy(MCore::Array::GetAddress(result), data.Get(), data.Length() * sizeof(T));
|
||||
@@ -162,6 +204,16 @@ struct MConverter<String>
|
||||
//#endif
|
||||
}
|
||||
|
||||
void ToManaged(String& result, const String& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(String& result, const String& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<String>& data)
|
||||
{
|
||||
if (data.Length() == 0)
|
||||
@@ -212,6 +264,16 @@ struct MConverter<StringAnsi>
|
||||
result = MUtils::ToStringAnsi((MString*)data);
|
||||
}
|
||||
|
||||
void ToManaged(StringAnsi& result, const StringAnsi& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(StringAnsi& result, const StringAnsi& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<StringAnsi>& data)
|
||||
{
|
||||
if (data.Length() == 0)
|
||||
@@ -262,6 +324,16 @@ struct MConverter<StringView>
|
||||
result = MUtils::ToString((MString*)data);
|
||||
}
|
||||
|
||||
void ToManaged(StringView& result, const StringView& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(StringView& result, const StringView& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<StringView>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
@@ -316,6 +388,16 @@ struct MConverter<Variant>
|
||||
result = MUtils::UnboxVariant(data);
|
||||
}
|
||||
|
||||
void ToManaged(Variant& result, const Variant& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(Variant& result, const Variant& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<Variant>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
@@ -365,6 +447,18 @@ struct MConverter<T*, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Va
|
||||
result = (T*)ScriptingObject::ToNative(data);
|
||||
}
|
||||
|
||||
void ToManaged(MObject*& result, const T* data)
|
||||
{
|
||||
//PLATFORM_DEBUG_BREAK; // FIXME
|
||||
result = data ? data->GetOrCreateManagedInstance() : nullptr;
|
||||
}
|
||||
|
||||
void ToNative(T*& result, const MObject* data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
result = (T*)ScriptingObject::ToNative(data);
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<T*>& data)
|
||||
{
|
||||
if (data.Length() == 0)
|
||||
@@ -405,9 +499,29 @@ struct MConverter<T, typename TEnableIf<TIsBaseOf<class ScriptingObject, T>::Val
|
||||
return data.GetOrCreateManagedInstance();
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<T>& data)
|
||||
void ToManaged(MObject*& result, const T& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(T& result, const MObject*& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
/*void ToManaged(MObject*& result, const T*& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(T*& result, const MObject*& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}*/
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<T>& data)
|
||||
{
|
||||
//PLATFORM_DEBUG_BREAK; // FIXME
|
||||
if (data.Length() == 0)
|
||||
return;
|
||||
MObject** objects = (MObject**)Allocator::Allocate(data.Length() * sizeof(MObject*));
|
||||
@@ -449,6 +563,16 @@ struct MConverter<ScriptingObjectReference<T>>
|
||||
result = (T*)ScriptingObject::ToNative(data);
|
||||
}
|
||||
|
||||
void ToManaged(MObject*& result, const ScriptingObjectReference<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(ScriptingObjectReference<T>& result, const MObject*& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<ScriptingObjectReference<T>>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
@@ -501,6 +625,17 @@ struct MConverter<AssetReference<T>>
|
||||
result = (T*)ScriptingObject::ToNative(data);
|
||||
}
|
||||
|
||||
void ToManaged(MObject*& result, const AssetReference<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
result = data.GetManagedInstance();
|
||||
}
|
||||
|
||||
void ToNative(AssetReference<T>& result, const MObject* data)
|
||||
{
|
||||
result = (T*)ScriptingObject::ToNative(data);
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<AssetReference<T>>& data)
|
||||
{
|
||||
if (data.Length() == 0)
|
||||
@@ -538,6 +673,29 @@ class SoftAssetReference;
|
||||
template<typename T>
|
||||
struct MConverter<SoftAssetReference<T>>
|
||||
{
|
||||
|
||||
template <typename U>
|
||||
void ToManaged(U& result, const SoftAssetReference<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
void ToNative(SoftAssetReference<T>& result, const U& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManaged(MObject*& result, const SoftAssetReference<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(SoftAssetReference<T>& result, const MObject*& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToManagedArray(MArray* result, const Span<SoftAssetReference<T>>& data)
|
||||
{
|
||||
//PLATFORM_DEBUG_BREAK; // FIXME
|
||||
@@ -575,6 +733,16 @@ struct MConverter<SoftAssetReference<T>>
|
||||
template<typename T>
|
||||
struct MConverter<Array<T>>
|
||||
{
|
||||
void ToManaged(Array<T>& result, const Array<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
void ToNative(Array<T>& result, const Array<T>& data)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
}
|
||||
|
||||
MObject* Box(const Array<T>& data, const MClass* klass)
|
||||
{
|
||||
PLATFORM_DEBUG_BREAK; // FIXME
|
||||
@@ -877,12 +1045,36 @@ namespace MUtils
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new managed array of data and copies contents from given native array.
|
||||
/// </summary>
|
||||
/// <param name="data">The array object.</param>
|
||||
/// <param name="valueClass">The array values type class.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
/*template<typename T, typename U>
|
||||
NativeArray<U> ToManagedArrayWrapper(const Span<T>& data, const MClass* valueClass)
|
||||
{
|
||||
if (!valueClass)
|
||||
return nullptr;
|
||||
MArray* result = MCore::Array::New(valueClass, data.Length());
|
||||
MConverter<T> converter;
|
||||
converter.ToManagedArray(result, data);
|
||||
return result;
|
||||
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<U> arr;
|
||||
arr.length = data.Count();
|
||||
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
|
||||
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(U));
|
||||
return arr;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T, typename AllocationType = HeapAllocation>
|
||||
/*template<typename T, typename AllocationType = HeapAllocation>
|
||||
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
@@ -893,22 +1085,233 @@ namespace MUtils
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T, typename U, typename AllocationType = HeapAllocation>
|
||||
FORCE_INLINE NativeArray<U> ToNativeArrayWrapper(const Array<T, AllocationType>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<U> arr;
|
||||
arr.length = data.Count();
|
||||
arr.data = (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true);
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T, U> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
arr.data[i] = converter.ToManaged(data[i]);
|
||||
return arr;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T, typename U>
|
||||
FORCE_INLINE NativeArray<U> ToManagedArrayWrapperConvert(const Span<T>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<U> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (U*)MCore::GC::AllocateMemory(arr.length * sizeof(U), true) : nullptr;
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T, U> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
converter.ToManaged(arr.data[i], data[i]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T>
|
||||
FORCE_INLINE NativeArray<T> ToNativeArrayWrapper(const Span<T>& data)
|
||||
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<T> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true);
|
||||
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
converter.ToNative(arr.data[i], data[i]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T, typename AllocationType = HeapAllocation>
|
||||
FORCE_INLINE void ToNativeArrayWrapperConvertGeneric(const Span<MObject*>& data, Array<T, AllocationType>& array)
|
||||
{
|
||||
if (!array.IsEmpty())
|
||||
PLATFORM_DEBUG_BREAK; // TODO: does the array require ClearDelete instead?
|
||||
|
||||
auto length = data.Length();
|
||||
array.Resize(length, false);
|
||||
//array.Clear();
|
||||
//array.EnsureCapacity(length);
|
||||
|
||||
MConverter<T> converter;
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
// Make sure the destination is default initialized first
|
||||
//array.AddUninitialized();
|
||||
//array.AddDefault();
|
||||
//T& dest = array.Get()[i];
|
||||
//new(&dest)AssetReference<T>();
|
||||
|
||||
// Convert from managed
|
||||
converter.ToNative(array.Get()[i], data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T, typename U>
|
||||
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperConvert(const Span<U>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<T> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T, U> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
converter.ToNative(arr.data[i], data[i]);
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T>
|
||||
FORCE_INLINE NativeArray<T> ToNativeArrayWrapperCopy(const Span<T>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<T> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
|
||||
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
/*FORCE_INLINE NativeArray<Char> ToManagedArrayWrapper(const Span<Char>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<Char> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = (Char*)MCore::GC::AllocateMemory(arr.length * sizeof(Char), true);
|
||||
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(Char));
|
||||
return arr;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T>
|
||||
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperConvert(const Span<T>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<T> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
|
||||
//Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
converter.ToManaged(arr.data[i], data[i]);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<typename T>
|
||||
FORCE_INLINE NativeArray<T> ToManagedArrayWrapperCopy(const Span<T>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<T> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (T*)MCore::GC::AllocateMemory(arr.length * sizeof(T), true) : nullptr;
|
||||
Platform::MemoryCopy(arr.data, data.Get(), arr.length * sizeof(T));
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
/*template<typename T>
|
||||
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T*>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<MObject*> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true);
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T*> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
{
|
||||
MObject*& ptr = arr.data[i];
|
||||
const T& asd = data[i];
|
||||
converter.ToManaged(ptr, asd);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}*/
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
/// <param name="data">The input data.</param>
|
||||
/// <returns>The output array.</returns>
|
||||
template<class T>
|
||||
FORCE_INLINE NativeArray<MObject*> ToManagedArrayWrapperPointer(const Span<T>& data)
|
||||
{
|
||||
// System.Runtime.InteropServices.Marshalling.ArrayMarshaller uses CoTask memory alloc to native data pointer
|
||||
NativeArray<MObject*> arr;
|
||||
arr.length = data.Length();
|
||||
arr.data = arr.length > 0 ? (MObject**)MCore::GC::AllocateMemory(arr.length * sizeof(MObject*), true) : nullptr;
|
||||
|
||||
// Convert to managed
|
||||
MConverter<T> converter;
|
||||
for (int i = 0; i < arr.length; ++i)
|
||||
converter.ToManaged(arr.data[i], data[i]);
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allocates new boolean array and copies data from the given unmanaged data container. The managed runtime is responsible for releasing the returned array data.
|
||||
/// </summary>
|
||||
|
||||
@@ -399,15 +399,15 @@ MObject* MCore::Object::Box(void* value, const MClass* klass)
|
||||
return (MObject*)CallStaticMethod<void*, void*, void*>(BoxValuePtr, klass->_handle, value);
|
||||
}
|
||||
|
||||
void* MCore::Object::Unbox(MObject* obj)
|
||||
void* MCore::Object::Unbox(const MObject* obj)
|
||||
{
|
||||
CRASH; // Should not be used anymore
|
||||
}
|
||||
|
||||
void MCore::Object::Unbox(MObject* obj, void* dest)
|
||||
void MCore::Object::Unbox(const MObject* obj, void* dest)
|
||||
{
|
||||
static void* UnboxValuePtr = GetStaticMethodPointer(TEXT("UnboxValue"));
|
||||
return CallStaticMethod<void, void*, void*>(UnboxValuePtr, obj, dest);
|
||||
return CallStaticMethod<void, const void*, void*>(UnboxValuePtr, obj, dest);
|
||||
}
|
||||
|
||||
MObject* MCore::Object::New(const MClass* klass)
|
||||
@@ -416,61 +416,61 @@ MObject* MCore::Object::New(const MClass* klass)
|
||||
return (MObject*)CallStaticMethod<void*, void*>(NewObjectPtr, klass->_handle);
|
||||
}
|
||||
|
||||
void MCore::Object::Init(MObject* obj)
|
||||
void MCore::Object::Init(const MObject* obj)
|
||||
{
|
||||
static void* ObjectInitPtr = GetStaticMethodPointer(TEXT("ObjectInit"));
|
||||
CallStaticMethod<void, void*>(ObjectInitPtr, obj);
|
||||
CallStaticMethod<void, const void*>(ObjectInitPtr, obj);
|
||||
}
|
||||
|
||||
MClass* MCore::Object::GetClass(MObject* obj)
|
||||
MClass* MCore::Object::GetClass(const MObject* obj)
|
||||
{
|
||||
ASSERT(obj);
|
||||
static void* GetObjectClassPtr = GetStaticMethodPointer(TEXT("GetObjectClass"));
|
||||
return (MClass*)CallStaticMethod<MClass*, void*>(GetObjectClassPtr, obj);
|
||||
return (MClass*)CallStaticMethod<MClass*, const void*>(GetObjectClassPtr, obj);
|
||||
}
|
||||
|
||||
MString* MCore::Object::ToString(MObject* obj)
|
||||
MString* MCore::Object::ToString(const MObject* obj)
|
||||
{
|
||||
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectString"));
|
||||
return (MString*)CallStaticMethod<void*, void*>(GetObjectStringPtr, obj);
|
||||
return (MString*)CallStaticMethod<void*, const void*>(GetObjectStringPtr, obj);
|
||||
}
|
||||
|
||||
int32 MCore::Object::GetHashCode(MObject* obj)
|
||||
int32 MCore::Object::GetHashCode(const MObject* obj)
|
||||
{
|
||||
static void* GetObjectStringPtr = GetStaticMethodPointer(TEXT("GetObjectHashCode"));
|
||||
return CallStaticMethod<int32, void*>(GetObjectStringPtr, obj);
|
||||
return CallStaticMethod<int32, const void*>(GetObjectStringPtr, obj);
|
||||
}
|
||||
|
||||
MString* MCore::String::GetEmpty(MDomain* domain)
|
||||
MString* MCore::String::GetEmpty(const MDomain* domain)
|
||||
{
|
||||
static void* GetStringEmptyPtr = GetStaticMethodPointer(TEXT("GetStringEmpty"));
|
||||
return (MString*)CallStaticMethod<void*>(GetStringEmptyPtr);
|
||||
}
|
||||
|
||||
MString* MCore::String::New(const char* str, int32 length, MDomain* domain)
|
||||
MString* MCore::String::New(const char* str, int32 length, const MDomain* domain)
|
||||
{
|
||||
static void* NewStringUTF8Ptr = GetStaticMethodPointer(TEXT("NewStringUTF8"));
|
||||
return (MString*)CallStaticMethod<void*, const char*, int>(NewStringUTF8Ptr, str, length);
|
||||
}
|
||||
|
||||
MString* MCore::String::New(const Char* str, int32 length, MDomain* domain)
|
||||
MString* MCore::String::New(const Char* str, int32 length, const MDomain* domain)
|
||||
{
|
||||
static void* NewStringUTF16Ptr = GetStaticMethodPointer(TEXT("NewStringUTF16"));
|
||||
return (MString*)CallStaticMethod<void*, const Char*, int>(NewStringUTF16Ptr, str, length);
|
||||
}
|
||||
|
||||
StringView MCore::String::GetChars(MString* obj)
|
||||
StringView MCore::String::GetChars(const MString* obj)
|
||||
{
|
||||
int32 length = 0;
|
||||
static void* GetStringPointerPtr = GetStaticMethodPointer(TEXT("GetStringPointer"));
|
||||
const Char* chars = CallStaticMethod<const Char*, void*, int*>(GetStringPointerPtr, obj, &length);
|
||||
const Char* chars = CallStaticMethod<const Char*, const void*, int*>(GetStringPointerPtr, obj, &length);
|
||||
return StringView(chars, length);
|
||||
}
|
||||
|
||||
void MCore::String::Free(MString* obj)
|
||||
void MCore::String::Free(const MString* obj)
|
||||
{
|
||||
static void* FreeStringPtr = GetStaticMethodPointer(TEXT("FreeString"));
|
||||
CallStaticMethod<void, void*>(FreeStringPtr, obj);
|
||||
CallStaticMethod<void, const void*>(FreeStringPtr, obj);
|
||||
}
|
||||
|
||||
MArray* MCore::Array::New(const MClass* elementKlass, int32 length)
|
||||
@@ -485,7 +485,7 @@ void MCore::Array::Free(const MArray* array)
|
||||
CallStaticMethod<void, void*>(FreeArrayPtr, (void*)array);
|
||||
}
|
||||
|
||||
MClass* MCore::Array::GetClass(MClass* elementKlass)
|
||||
MClass* MCore::Array::GetClass(const MClass* elementKlass)
|
||||
{
|
||||
static void* GetArrayTypeFromElementTypePtr = GetStaticMethodPointer(TEXT("GetArrayTypeFromElementType"));
|
||||
MType* typeHandle = (MType*)CallStaticMethod<void*, void*>(GetArrayTypeFromElementTypePtr, elementKlass->_handle);
|
||||
@@ -511,24 +511,24 @@ void* MCore::Array::GetAddress(const MArray* obj)
|
||||
return CallStaticMethod<void*, void*>(GetArrayPointerPtr, (void*)obj);
|
||||
}
|
||||
|
||||
MArray* MCore::Array::Unbox(MObject* obj)
|
||||
MArray* MCore::Array::Unbox(const MObject* obj)
|
||||
{
|
||||
static void* GetArrayPtr = GetStaticMethodPointer(TEXT("GetArray"));
|
||||
return (MArray*)CallStaticMethod<void*, void*>(GetArrayPtr, (void*)obj);
|
||||
}
|
||||
|
||||
MGCHandle MCore::GCHandle::New(MObject* obj, bool pinned)
|
||||
MGCHandle MCore::GCHandle::New(const MObject* obj, bool pinned)
|
||||
{
|
||||
ASSERT(obj);
|
||||
static void* NewGCHandlePtr = GetStaticMethodPointer(TEXT("NewGCHandle"));
|
||||
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandlePtr, obj, pinned);
|
||||
return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandlePtr, obj, pinned);
|
||||
}
|
||||
|
||||
MGCHandle MCore::GCHandle::NewWeak(MObject* obj, bool trackResurrection)
|
||||
MGCHandle MCore::GCHandle::NewWeak(const MObject* obj, bool trackResurrection)
|
||||
{
|
||||
ASSERT(obj);
|
||||
static void* NewGCHandleWeakPtr = GetStaticMethodPointer(TEXT("NewGCHandleWeak"));
|
||||
return (MGCHandle)CallStaticMethod<void*, void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection);
|
||||
return (MGCHandle)CallStaticMethod<void*, const void*, bool>(NewGCHandleWeakPtr, obj, trackResurrection);
|
||||
}
|
||||
|
||||
MObject* MCore::GCHandle::GetTarget(const MGCHandle& handle)
|
||||
@@ -1387,28 +1387,28 @@ int32 MField::GetOffset() const
|
||||
return _fieldOffset;
|
||||
}
|
||||
|
||||
void MField::GetValue(MObject* instance, void* result) const
|
||||
void MField::GetValue(const MObject* instance, void* result) const
|
||||
{
|
||||
static void* FieldGetValuePtr = GetStaticMethodPointer(TEXT("FieldGetValue"));
|
||||
CallStaticMethod<void, void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
|
||||
CallStaticMethod<void, const void*, void*, void*>(FieldGetValuePtr, instance, _handle, result);
|
||||
}
|
||||
|
||||
void MField::GetValueReference(MObject* instance, void* result) const
|
||||
void MField::GetValueReference(const MObject* instance, void* result) const
|
||||
{
|
||||
static void* FieldGetValueReferencePtr = GetStaticMethodPointer(TEXT("FieldGetValueReference"));
|
||||
CallStaticMethod<void, void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
|
||||
CallStaticMethod<void, const void*, void*, int, void*>(FieldGetValueReferencePtr, instance, _handle, _fieldOffset, result);
|
||||
}
|
||||
|
||||
MObject* MField::GetValueBoxed(MObject* instance) const
|
||||
MObject* MField::GetValueBoxed(const MObject* instance) const
|
||||
{
|
||||
static void* FieldGetValueBoxedPtr = GetStaticMethodPointer(TEXT("FieldGetValueBoxed"));
|
||||
return CallStaticMethod<MObject*, void*, void*>(FieldGetValueBoxedPtr, instance, _handle);
|
||||
return CallStaticMethod<MObject*, const void*, void*>(FieldGetValueBoxedPtr, instance, _handle);
|
||||
}
|
||||
|
||||
void MField::SetValue(MObject* instance, void* value) const
|
||||
void MField::SetValue(const MObject* instance, void* value) const
|
||||
{
|
||||
static void* FieldSetValuePtr = GetStaticMethodPointer(TEXT("FieldSetValue"));
|
||||
CallStaticMethod<void, void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
|
||||
CallStaticMethod<void, const void*, void*, void*>(FieldSetValuePtr, instance, _handle, value);
|
||||
}
|
||||
|
||||
bool MField::HasAttribute(const MClass* klass) const
|
||||
|
||||
@@ -245,7 +245,7 @@ void* ScriptingObject::ToInterface(ScriptingObject* obj, const ScriptingTypeHand
|
||||
return result;
|
||||
}
|
||||
|
||||
ScriptingObject* ScriptingObject::ToNative(MObject* obj)
|
||||
ScriptingObject* ScriptingObject::ToNative(const MObject* obj)
|
||||
{
|
||||
ScriptingObject* ptr = nullptr;
|
||||
#if USE_CSHARP
|
||||
|
||||
@@ -132,7 +132,7 @@ public:
|
||||
return (T*)ToInterface(obj, T::TypeInitializer);
|
||||
}
|
||||
|
||||
static ScriptingObject* ToNative(MObject* obj);
|
||||
static ScriptingObject* ToNative(const MObject* obj);
|
||||
|
||||
FORCE_INLINE static MObject* ToManaged(const ScriptingObject* obj)
|
||||
{
|
||||
|
||||
@@ -635,44 +635,60 @@ namespace Flax.Build.Bindings
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
|
||||
else if (functionInfo.ReturnType.IsArrayOrSpan || returnNativeType == "Array")
|
||||
{
|
||||
var elementApiType = functionInfo.ReturnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, functionInfo.ReturnType.GenericArgs[0], caller) : null;
|
||||
string unmanagedType = "";
|
||||
if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
|
||||
//if (functionInfo.ReturnType.GenericArgs != null && functionInfo.ReturnType.GenericArgs[0].IsPod(buildData, caller))
|
||||
var genericType = functionInfo.ReturnType.GenericArgs?[0].Type;
|
||||
if (functionInfo.ReturnType.Type == "BytesContainer")
|
||||
genericType = "byte";
|
||||
if (functionInfo.ReturnType.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
|
||||
genericType = null;
|
||||
|
||||
switch (genericType)
|
||||
{
|
||||
switch (functionInfo.ReturnType.GenericArgs[0].Type)
|
||||
{
|
||||
case "bool": unmanagedType = "U1"; break;
|
||||
case "byte": unmanagedType = "U1"; break;
|
||||
case "sbyte": unmanagedType = "I1"; break;
|
||||
case "char": unmanagedType = "I2"; break;
|
||||
case "short": case "int16": unmanagedType = "I2"; break;
|
||||
case "ushort": case "uint16": unmanagedType = "U2"; break;
|
||||
case "int": case "int32": unmanagedType = "I4"; break;
|
||||
case "uint": case "uint32": unmanagedType = "U4"; break;
|
||||
case "long": case "int64": unmanagedType = "I8"; break;
|
||||
case "ulong": case "uint64": unmanagedType = "U8"; break;
|
||||
case "float": unmanagedType = "R4"; break;
|
||||
case "double": unmanagedType = "R8"; break;
|
||||
case "bool": unmanagedType = "U1"; break;
|
||||
case "byte": unmanagedType = "U1"; break;
|
||||
case "sbyte": unmanagedType = "I1"; break;
|
||||
case "char": unmanagedType = "I2"; break;
|
||||
case "short": case "int16": unmanagedType = "I2"; break;
|
||||
case "ushort": case "uint16": unmanagedType = "U2"; break;
|
||||
case "int": case "int32": unmanagedType = "I4"; break;
|
||||
case "uint": case "uint32": unmanagedType = "U4"; break;
|
||||
case "long": case "int64": unmanagedType = "I8"; break;
|
||||
case "ulong": case "uint64": unmanagedType = "U8"; break;
|
||||
case "float": unmanagedType = "R4"; break;
|
||||
case "double": unmanagedType = "R8"; break;
|
||||
|
||||
case "Float2":
|
||||
case "Double2":
|
||||
case "Vector2":
|
||||
case "Float3":
|
||||
case "Double3":
|
||||
case "Vector3":
|
||||
case "Float4":
|
||||
case "Double4":
|
||||
case "Vector4":
|
||||
case "Color":
|
||||
case "Color32":
|
||||
case "Guid":
|
||||
unmanagedType = "Any"; // FIXME
|
||||
break;
|
||||
case "Float2":
|
||||
case "Double2":
|
||||
case "Vector2":
|
||||
case "Float3":
|
||||
case "Double3":
|
||||
case "Vector3":
|
||||
case "Float4":
|
||||
case "Double4":
|
||||
case "Vector4":
|
||||
case "Color":
|
||||
case "Color32":
|
||||
case "Guid":
|
||||
unmanagedType = "Any"; // FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
unmanagedType = "Any";
|
||||
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
|
||||
break;
|
||||
}
|
||||
case null:
|
||||
case "":
|
||||
case "String":
|
||||
case "StringAnsi":
|
||||
case "StringView":
|
||||
unmanagedType = null;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
|
||||
unmanagedType = null;
|
||||
else
|
||||
unmanagedType = "Any";
|
||||
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
|
||||
break;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(unmanagedType))
|
||||
{
|
||||
@@ -681,18 +697,22 @@ namespace Flax.Build.Bindings
|
||||
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
|
||||
returnMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__returnCount"))})";
|
||||
}
|
||||
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
|
||||
returnMarshalType = $"/*marsh2c*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<string, IntPtr>), CountElementName = \"__returnCount\")";
|
||||
else if (elementApiType?.IsValueType ?? true)
|
||||
returnMarshalType = $"/*marsh2a*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
else
|
||||
returnMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
returnMarshalType = $"/*marsh2b*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
}
|
||||
else if (functionInfo.ReturnType.Type == "Array" || functionInfo.ReturnType.Type == "Span" || functionInfo.ReturnType.Type == "DataContainer" || functionInfo.ReturnType.Type == "BytesContainer" || returnNativeType == "Array")
|
||||
{
|
||||
//[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.U1, SizeParamIndex = 8)]
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
|
||||
returnMarshalType = "/*marsh3*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = nameof(__returnCount))";
|
||||
}
|
||||
else if (functionInfo.ReturnType.Type == "Dictionary")
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
else if (returnValueType == "byte[]")
|
||||
returnMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
returnMarshalType = "/*marsh4*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__returnCount\")";
|
||||
else if (returnValueType == "bool[]")
|
||||
{
|
||||
// Boolean arrays does not support custom marshalling for some unknown reason
|
||||
@@ -742,44 +762,65 @@ namespace Flax.Build.Bindings
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.SystemObjectArrayMarshaller))";
|
||||
else if (parameterInfo.Type.IsArrayOrSpan || nativeType == "Array")
|
||||
{
|
||||
var elementApiType = parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
|
||||
string unmanagedType = "";
|
||||
if (parameterInfo.Type.GenericArgs != null && parameterInfo.Type.GenericArgs[0].IsPod(buildData, caller))
|
||||
var genericType = parameterInfo.Type.GenericArgs?[0].Type;
|
||||
if (parameterInfo.Type.Type == "BytesContainer")
|
||||
genericType = "byte";
|
||||
if (parameterInfo.Type.IsObjectRef || (elementApiType?.IsScriptingObject ?? false))
|
||||
genericType = null;
|
||||
|
||||
switch (genericType)
|
||||
{
|
||||
switch (parameterInfo.Type.GenericArgs[0].Type)
|
||||
{
|
||||
case "bool": unmanagedType = "U1"; break;
|
||||
case "byte": unmanagedType = "U1"; break;
|
||||
case "sbyte": unmanagedType = "I1"; break;
|
||||
case "char": unmanagedType = "I2"; break;
|
||||
case "short": case "int16": unmanagedType = "I2"; break;
|
||||
case "ushort": case "uint16": unmanagedType = "U2"; break;
|
||||
case "int": case "int32": unmanagedType = "I4"; break;
|
||||
case "uint": case "uint32": unmanagedType = "U4"; break;
|
||||
case "long": case "int64": unmanagedType = "I8"; break;
|
||||
case "ulong": case "uint64": unmanagedType = "U8"; break;
|
||||
case "float": unmanagedType = "R4"; break;
|
||||
case "double": unmanagedType = "R8"; break;
|
||||
case "bool": unmanagedType = "U1"; break;
|
||||
case "byte": unmanagedType = "U1"; break;
|
||||
case "sbyte": unmanagedType = "I1"; break;
|
||||
case "char": unmanagedType = "I2"; break;
|
||||
case "short": case "int16": unmanagedType = "I2"; break;
|
||||
case "ushort": case "uint16": unmanagedType = "U2"; break;
|
||||
case "int": case "int32": unmanagedType = "I4"; break;
|
||||
case "uint": case "uint32": unmanagedType = "U4"; break;
|
||||
case "long": case "int64": unmanagedType = "I8"; break;
|
||||
case "ulong": case "uint64": unmanagedType = "U8"; break;
|
||||
case "float": unmanagedType = "R4"; break;
|
||||
case "double": unmanagedType = "R8"; break;
|
||||
|
||||
case "Float2":
|
||||
case "Double2":
|
||||
case "Vector2":
|
||||
case "Float3":
|
||||
case "Double3":
|
||||
case "Vector3":
|
||||
case "Float4":
|
||||
case "Double4":
|
||||
case "Vector4":
|
||||
case "Color":
|
||||
case "Color32":
|
||||
case "Guid":
|
||||
unmanagedType = "Any"; // FIXME
|
||||
break;
|
||||
case "Float2":
|
||||
case "Double2":
|
||||
case "Vector2":
|
||||
case "Float3":
|
||||
case "Double3":
|
||||
case "Vector3":
|
||||
case "Float4":
|
||||
case "Double4":
|
||||
case "Vector4":
|
||||
case "Color":
|
||||
case "Color32":
|
||||
case "Guid":
|
||||
unmanagedType = "Any"; // FIXME
|
||||
break;
|
||||
|
||||
default:
|
||||
unmanagedType = "Any";
|
||||
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
|
||||
break;
|
||||
}
|
||||
case null:
|
||||
case "":
|
||||
case "String":
|
||||
case "StringAnsi":
|
||||
case "StringView":
|
||||
unmanagedType = null;
|
||||
break;
|
||||
|
||||
case "AntiRollBar":
|
||||
unmanagedType = "Any"; // FIXME: This looks like a POD-type but isn't one?
|
||||
break;
|
||||
|
||||
default:
|
||||
if (elementApiType != null && (elementApiType.IsClass || !elementApiType.IsPod))
|
||||
unmanagedType = null;
|
||||
else if (elementApiType == null)
|
||||
unmanagedType = "Any";
|
||||
else
|
||||
unmanagedType = "Any";
|
||||
//Log.Warning($"unknown type: '{parameterInfo.Type.GenericArgs[0].Type}'");
|
||||
break;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(unmanagedType))
|
||||
{
|
||||
@@ -788,10 +829,28 @@ namespace Flax.Build.Bindings
|
||||
arraySubType = $"ArraySubType = UnmanagedType.{unmanagedType}, ";
|
||||
parameterMarshalType = $"MarshalAs(UnmanagedType.LPArray, {arraySubType}SizeParamIndex = {(!functionInfo.IsStatic ? 1 : 0) + functionInfo.Parameters.Count + (functionInfo.Glue.CustomParameters.FindIndex(x => x.Name == $"__{parameterInfo.Name}Count"))})";
|
||||
}
|
||||
else if (genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
|
||||
parameterMarshalType = $"/*marsh5c*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<string, IntPtr>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
else if (elementApiType.IsValueType)
|
||||
{
|
||||
var nativeName = parameterInfo.Type.GetFullNameNative(buildData, caller);
|
||||
var nativeInternalName = GenerateCppManagedWrapperName(elementApiType);
|
||||
var marshallerName = (!string.IsNullOrEmpty(elementApiType?.Namespace) ? $"{elementApiType?.Namespace}.Interop." : "") + $"{elementApiType.Name}Marshaller";
|
||||
//parameterMarshalType = $"/*marsh5a pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
if (/*nativeName != nativeInternalName && */elementApiType.MarshalAs != null)
|
||||
parameterMarshalType = $"/*marsh5a1 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
else
|
||||
parameterMarshalType = $"/*marsh5a2 pod:{elementApiType.IsPod}*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<{elementApiType.Name},{marshallerName}.{elementApiType.Name}Internal>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
//parameterMarshalType += $"] [MarshalUsing(typeof({marshallerName}), ElementIndirectionDepth = 1)";
|
||||
// [MarshalUsing(typeof(ExampleMarshaller), ElementIndirectionDepth = 1)]
|
||||
}
|
||||
else
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
parameterMarshalType = $"/*marsh5b*/MarshalUsing(typeof(FlaxEngine.Interop.BoxedArrayMarshaller<,>), CountElementName = \"__{parameterInfo.Name}Count\")";
|
||||
if (!parameterInfo.IsOut && !parameterInfo.IsRef)
|
||||
parameterMarshalType += ", In"; // The usage of 'LibraryImportAttribute' does not follow recommendations. It is recommended to use explicit '[In]' and '[Out]' attributes on array parameters.
|
||||
|
||||
//if (elementApiType?.MarshalAs != null)
|
||||
// parameterMarshalType += $"] [MarshalUsing(typeof({elementApiType.MarshalAs}), ElementIndirectionDepth = 1)";
|
||||
}
|
||||
else if (parameterInfo.Type.Type == "Dictionary")
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
@@ -801,7 +860,7 @@ namespace Flax.Build.Bindings
|
||||
parameterMarshalType = "MarshalAs(UnmanagedType.I2)";
|
||||
else if (nativeType.EndsWith("[]"))
|
||||
{
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>))";
|
||||
parameterMarshalType = $"/*marsh6*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>))";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(parameterMarshalType))
|
||||
@@ -841,7 +900,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
// TODO: make this code shared with MarshalUsing selection from the above
|
||||
if (parameterInfo.Type.IsArrayOrSpan)
|
||||
parameterMarshalType = $"MarshalUsing(typeof(FlaxEngine.Interop.ArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
|
||||
parameterMarshalType = $"/*marsh1*/MarshalUsing(typeof(FlaxEngine.Interop.NativeArrayMarshaller<,>), CountElementName = \"{parameterInfo.Name}Count\")";
|
||||
else if (parameterInfo.Type.Type == "Dictionary")
|
||||
parameterMarshalType = "MarshalUsing(typeof(FlaxEngine.Interop.DictionaryMarshaller<,>), ConstantElementCount = 0)";
|
||||
else if (parameterInfo.Type.Type == "CultureInfo")
|
||||
@@ -1806,11 +1865,22 @@ namespace Flax.Build.Bindings
|
||||
type = "IntPtr";
|
||||
else if (marshalType.IsPtr && !originalType.EndsWith("*"))
|
||||
type = "IntPtr";
|
||||
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer")
|
||||
else if (marshalType.IsArrayOrSpan)
|
||||
{
|
||||
type = "IntPtr";
|
||||
apiType = FindApiTypeInfo(buildData, marshalType.GenericArgs[0], structureInfo);
|
||||
internalType = apiType is StructureInfo elementStructureInfo && UseCustomMarshalling(buildData, elementStructureInfo, structureInfo);
|
||||
string originalElementType = originalType.Substring(0, originalType.Length - 2);
|
||||
if (internalType)
|
||||
{
|
||||
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
|
||||
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
|
||||
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
|
||||
type = $"NativeArray<{internalElementType}>";
|
||||
}
|
||||
else if (marshalType.GenericArgs[0].IsObjectRef)
|
||||
type = "NativeArray<IntPtr>";
|
||||
else
|
||||
type = $"NativeArray<{originalElementType}>";
|
||||
}
|
||||
else if (marshalType.Type == "Version")
|
||||
type = "IntPtr";
|
||||
@@ -1827,12 +1897,14 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
//else if (type == "Guid")
|
||||
// type = "GuidNative";
|
||||
structContents.Append($"{type} {fieldInfo.Name};").Append(type == "IntPtr" ? $" // {originalType}" : "").AppendLine();
|
||||
structContents.Append($"{type} {fieldInfo.Name};").Append(type != originalType ? $" // {originalType}" : "").AppendLine();
|
||||
}
|
||||
|
||||
// Generate struct constructor/getter and deconstructor/setter function
|
||||
toManagedContent.Append("managed.").Append(fieldInfo.Name).Append(" = ");
|
||||
toNativeContent.Append("unmanaged.").Append(fieldInfo.Name).Append(" = ");
|
||||
var managedField = $"managed.{fieldInfo.Name}";
|
||||
var unmanagedField = $"unmanaged.{fieldInfo.Name}";
|
||||
toManagedContent.Append($"{managedField} = ");
|
||||
toNativeContent.Append($"{unmanagedField} = ");
|
||||
if (marshalType.IsObjectRef)
|
||||
{
|
||||
var managedType = GenerateCSharpNativeToManaged(buildData, marshalType.GenericArgs[0], structureInfo);
|
||||
@@ -1868,7 +1940,7 @@ namespace Flax.Build.Bindings
|
||||
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
|
||||
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Free(); }}");
|
||||
}
|
||||
else if (marshalType.Type == "Array" || marshalType.Type == "Span" || marshalType.Type == "DataContainer" || marshalType.Type == "BytesContainer")
|
||||
else if (marshalType.IsArrayOrSpan)
|
||||
{
|
||||
string originalElementType = originalType.Substring(0, originalType.Length - 2);
|
||||
if (internalType)
|
||||
@@ -1877,17 +1949,17 @@ namespace Flax.Build.Bindings
|
||||
string originalElementTypeMarshaller = (!string.IsNullOrEmpty(apiType?.Namespace) ? $"{apiType?.Namespace}.Interop." : "") + $"{originalElementType}Marshaller";
|
||||
string originalElementTypeName = originalElementType.Substring(originalElementType.LastIndexOf('.') + 1); // Strip namespace
|
||||
string internalElementType = $"{originalElementTypeMarshaller}.{originalElementTypeName}Internal";
|
||||
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.ConvertArray((Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToSpan<{internalElementType}>(), {originalElementTypeMarshaller}.ToManaged) : null;");
|
||||
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(NativeInterop.ConvertArray(managed.{fieldInfo.Name}, {originalElementTypeMarshaller}.ToNative)), GCHandleType.Weak) : IntPtr.Zero;");
|
||||
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<{internalElementType}> values = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<{internalElementType}>(); foreach (var value in values) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.ConvertArray({unmanagedField}.AsSpan(), {originalElementTypeMarshaller}.ToManaged) : null;");
|
||||
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ConvertArrayNative({managedField}.AsSpan(), {originalElementTypeMarshaller}.ToNative) : new NativeArray<{internalElementType}>();");
|
||||
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.Free(value); }} {unmanagedField}.Free(); }}");
|
||||
freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var value in {unmanagedField}.AsReadOnlySpan()) {{ {originalElementTypeMarshaller}.NativeToManaged.Free(value); }} {unmanagedField}.Free(); }}");
|
||||
}
|
||||
else if (marshalType.GenericArgs[0].IsObjectRef)
|
||||
{
|
||||
// Array elements passed as GCHandles
|
||||
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>(Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)) : null;");
|
||||
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name})/*, GCHandleType.Weak*/) : IntPtr.Zero;");
|
||||
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? NativeInterop.GCHandleArrayToManagedArray<{originalElementType}>({unmanagedField}) : null;");
|
||||
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? NativeInterop.ManagedArrayToGCHandleWrappedArray(managed.{fieldInfo.Name}) : new NativeArray<IntPtr>();");
|
||||
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ foreach (var ptr in {unmanagedField}.AsReadOnlySpan()) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} {unmanagedField}.Free(); }}");
|
||||
|
||||
// Permanent ScriptingObject handle is passed from native side, do not release it
|
||||
//freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); Span<IntPtr> ptrs = (Unsafe.As<ManagedArray>(handle.Target)).ToSpan<IntPtr>(); foreach (var ptr in ptrs) {{ if (ptr != IntPtr.Zero) {{ ManagedHandle.FromIntPtr(ptr).Free(); }} }} (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
@@ -1895,10 +1967,10 @@ namespace Flax.Build.Bindings
|
||||
else
|
||||
{
|
||||
// Blittable array elements
|
||||
toManagedContent.AppendLine($"unmanaged.{fieldInfo.Name} != IntPtr.Zero ? (Unsafe.As<ManagedArray>(ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}).Target)).ToArray<{originalElementType}>() : null;");
|
||||
toNativeContent.AppendLine($"managed.{fieldInfo.Name}?.Length > 0 ? ManagedHandle.ToIntPtr(ManagedArray.WrapNewArray(managed.{fieldInfo.Name}), GCHandleType.Weak) : IntPtr.Zero;");
|
||||
freeContents.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
freeContents2.AppendLine($"if (unmanaged.{fieldInfo.Name} != IntPtr.Zero) {{ ManagedHandle handle = ManagedHandle.FromIntPtr(unmanaged.{fieldInfo.Name}); (Unsafe.As<ManagedArray>(handle.Target)).Free(); handle.Free(); }}");
|
||||
toManagedContent.AppendLine($"{unmanagedField} != IntPtr.Zero ? {unmanagedField}.AsReadOnlySpan().ToArray() : null;");
|
||||
toNativeContent.AppendLine($"{managedField}?.Length > 0 ? new NativeArray<{originalElementType}>({managedField}.AsSpan()) : new NativeArray<{originalElementType}>();");
|
||||
freeContents.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
|
||||
freeContents2.AppendLine($"if ({unmanagedField} != IntPtr.Zero) {{ {unmanagedField}.Free(); }}");
|
||||
}
|
||||
}
|
||||
else if (marshalType.Type == "Version")
|
||||
|
||||
@@ -18,6 +18,27 @@ namespace Flax.Build.Bindings
|
||||
/// The parameter needs to be assigned to local variable first.
|
||||
/// </summary>
|
||||
NeedLocalVariable = 1 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// The parameter needs an additional length parameter.
|
||||
/// </summary>
|
||||
LengthParameter = 2 << 0,
|
||||
|
||||
/// <summary>
|
||||
/// The parameter needs to be assigned as a parameter reference.
|
||||
/// </summary>
|
||||
AssignAsReference = 3 << 0,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ParameterGeneratorFlags
|
||||
{
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The parameter needs to be assigned as a parameter reference.
|
||||
/// </summary>
|
||||
AssignAsReference = 1 << 0,
|
||||
}
|
||||
|
||||
partial class BindingsGenerator
|
||||
@@ -38,6 +59,7 @@ namespace Flax.Build.Bindings
|
||||
private static readonly Dictionary<string, TypeInfo> CppVariantToTypes = new Dictionary<string, TypeInfo>();
|
||||
private static readonly Dictionary<string, TypeInfo> CppVariantFromTypes = new Dictionary<string, TypeInfo>();
|
||||
private static bool CppNonPodTypesConvertingGeneration = false;
|
||||
private static bool CppNativeArrayAsParameter = false;
|
||||
private static StringBuilder CppContentsEnd;
|
||||
|
||||
public class ScriptingLangInfo
|
||||
@@ -88,9 +110,13 @@ namespace Flax.Build.Bindings
|
||||
"Rectangle",
|
||||
};
|
||||
|
||||
private static ParameterFormattingFlags SetFlag(this ParameterFormattingFlags flags, ParameterFormattingFlags value, bool enable)
|
||||
private static ParameterFormattingFlags SetFlag(this ref ParameterFormattingFlags flags, ParameterFormattingFlags value, bool enable)
|
||||
{
|
||||
return enable ? (flags | value) : (flags & ~value);
|
||||
return flags = enable ? (flags | value) : (flags & ~value);
|
||||
}
|
||||
private static ParameterGeneratorFlags SetFlag(this ref ParameterGeneratorFlags flags, ParameterGeneratorFlags value, bool enable)
|
||||
{
|
||||
return flags = enable ? (flags | value) : (flags & ~value);
|
||||
}
|
||||
|
||||
private static bool GenerateCppIsTemplateInstantiationType(ApiTypeInfo typeInfo)
|
||||
@@ -121,12 +147,14 @@ namespace Flax.Build.Bindings
|
||||
private static string GenerateCppWrapperNativeToManagedParam(BuildData buildData, StringBuilder contents, TypeInfo paramType, string paramName, ApiTypeInfo caller, bool isRef, out ParameterFormattingFlags formattingFlags)
|
||||
{
|
||||
formattingFlags = ParameterFormattingFlags.None;
|
||||
//CppNativeArrayAsParameter = true;
|
||||
var nativeToManaged = GenerateCppWrapperNativeToManaged(buildData, paramType, caller, out var managedTypeAsNative, null);
|
||||
//CppNativeArrayAsParameter = false;
|
||||
string result;
|
||||
if (!string.IsNullOrEmpty(nativeToManaged))
|
||||
{
|
||||
result = string.Format(nativeToManaged, paramName);
|
||||
if (managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' && !isRef)
|
||||
if ((managedTypeAsNative[managedTypeAsNative.Length - 1] == '*' || managedTypeAsNative.StartsWith("NativeArray<")) && !isRef)
|
||||
{
|
||||
// Pass pointer value
|
||||
}
|
||||
@@ -135,6 +163,7 @@ namespace Flax.Build.Bindings
|
||||
// Pass as pointer to local variable converted for managed runtime
|
||||
if (paramType.IsPtr)
|
||||
result = string.Format(nativeToManaged, '*' + paramName);
|
||||
contents.Append($" // localvar1 {managedTypeAsNative}, {paramType.ToString()}").AppendLine();
|
||||
contents.Append($" auto __param_orig_{paramName} = {result};").AppendLine();
|
||||
contents.Append($" auto __param_{paramName} = __param_orig_{paramName};").AppendLine();
|
||||
result = $"&__param_{paramName}";
|
||||
@@ -543,30 +572,28 @@ namespace Flax.Build.Bindings
|
||||
return "{0}.GetManagedInstance()";
|
||||
}
|
||||
|
||||
// Array or DataContainer
|
||||
if ((typeInfo.Type == "Array" || typeInfo.Type == "Span" || typeInfo.Type == "DataContainer") && typeInfo.GenericArgs != null)
|
||||
#if !USE_NETCORE
|
||||
// BytesContainer
|
||||
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
{
|
||||
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||
#if USE_NETCORE
|
||||
if (arrayApiType?.IsPod ?? false)
|
||||
{
|
||||
if (functionInfo == null)
|
||||
{
|
||||
// Storage type should be wrapped
|
||||
type = $"NativeArray<{arrayApiType.FullNameNative}>";
|
||||
return $"MUtils::ToNativeArrayWrapper<{arrayApiType.FullNameNative}>({{0}})/*sahho*/";
|
||||
}
|
||||
else
|
||||
{
|
||||
//type = arrayApiType.FullNameNative + "*/*wahho*/";
|
||||
type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
|
||||
//if (arrayTypeInfo.Type == "bool")
|
||||
// return "MUtils::ToBoolArray({0})/*bahho*/";
|
||||
return "MUtils::ToNativeArrayWrapper({0})/*nahhoa7eatra*/";
|
||||
}
|
||||
}
|
||||
type = "MArray*";
|
||||
return "MUtils::ToArray({0})";
|
||||
}
|
||||
|
||||
// Span
|
||||
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
|
||||
{
|
||||
type = "MonoArray*";
|
||||
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Array or DataContainer
|
||||
if (typeInfo.IsArrayOrSpan)
|
||||
{
|
||||
var arrayTypeInfo = typeInfo.GenericArgs?.Count > 0 ? typeInfo.GenericArgs[0] : null;
|
||||
var arrayApiType = arrayTypeInfo != null ? FindApiTypeInfo(buildData, arrayTypeInfo, caller) : null;
|
||||
|
||||
type = "MArray*";
|
||||
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||
{
|
||||
@@ -576,25 +603,98 @@ namespace Flax.Build.Bindings
|
||||
var genericArgs = arrayApiType.MarshalAs.GetFullNameNative(buildData, caller);
|
||||
if (typeInfo.GenericArgs.Count != 1)
|
||||
genericArgs += ", " + typeInfo.GenericArgs[1];
|
||||
return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
|
||||
return "MUtils::ToArray(Array<" + genericArgs + ">({0}), " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")/*marshalas*/";
|
||||
}
|
||||
return "MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
|
||||
}
|
||||
|
||||
#if !USE_NETCORE
|
||||
// Span
|
||||
if (typeInfo.Type == "Span" && typeInfo.GenericArgs != null)
|
||||
{
|
||||
type = "MonoArray*";
|
||||
return "MUtils::Span({0}, " + GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, functionInfo) + ")";
|
||||
}
|
||||
#if USE_NETCORE
|
||||
if (typeInfo.Type == "BytesContainer")
|
||||
{
|
||||
type = "NativeArray<byte> /*baggo*/";
|
||||
return "MUtils::ToManagedArrayWrapperCopy<byte>({0})/*bagtgaggag*/";
|
||||
}
|
||||
else //if (arrayApiType?.IsValueType ?? true)
|
||||
{
|
||||
var nativeName = /*arrayApiType?.FullNameNative ?? */arrayTypeInfo.GetFullNameNative(buildData, caller);
|
||||
var nativeInternalName = nativeName;
|
||||
var converter = "{0}";
|
||||
var castType = nativeName;
|
||||
bool pod = true;
|
||||
|
||||
if (arrayApiType != null && arrayApiType.IsStruct && !arrayApiType.IsPod)
|
||||
{
|
||||
if (!CppUsedNonPodTypes.Contains(arrayApiType))
|
||||
CppUsedNonPodTypes.Add(arrayApiType);
|
||||
pod = false;
|
||||
// Requires conversion
|
||||
//converter = "ToManaged({0})";
|
||||
//nativeInternalName = !string.IsNullOrEmpty(arrayApiType?.FullNameNativeInternal) ? arrayApiType.FullNameNativeInternal + "Managed" : null;
|
||||
nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
|
||||
castType = nativeInternalName;
|
||||
//nativeName = nativeInternalName;
|
||||
|
||||
}
|
||||
|
||||
/*if (arrayTypeInfo.GenericArgs?.Count > 0)
|
||||
{
|
||||
nativeInternalName += "<";
|
||||
for (int i=0; i< arrayTypeInfo.GenericArgs.Count; ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
nativeInternalName += ", ";
|
||||
nativeInternalName += arrayTypeInfo.GenericArgs[i].Type;
|
||||
}
|
||||
nativeInternalName += ">";
|
||||
}*/
|
||||
//else
|
||||
// nativeInternalName = nativeName;
|
||||
if (typeInfo.Type != "Span")
|
||||
{
|
||||
//converter = "ToSpan({0})";
|
||||
/*if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
|
||||
converter = $"(const Span<{nativeName}*>&)ToSpan({{0}})";
|
||||
else*/
|
||||
converter = $"(const Span<{nativeName}>&)ToSpan({{0}})";
|
||||
//converter = $"Span<{nativeInternalName}>({{0}}.Get(), {{0}}.Count())";
|
||||
}
|
||||
if (CppNativeArrayAsParameter)
|
||||
{
|
||||
type = nativeName + $"*/*wahho2 pod:{pod}*/";
|
||||
//type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
|
||||
//if (arrayTypeInfo.Type == "bool")
|
||||
// return "MUtils::ToBoolArray({0})/*bahho*/";
|
||||
return $"({castType}*)MUtils::ToManagedArrayWrapperCopy({converter})/*sahho1*/";
|
||||
}
|
||||
else if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
|
||||
{
|
||||
type = $"NativeArray<MObject*>/*wahho5 object*/";
|
||||
return $"MUtils::ToManagedArrayWrapperPointer<{nativeName}>({converter})/*sahho3a*/";
|
||||
}
|
||||
else if (arrayApiType != null && arrayApiType.IsScriptingObject)
|
||||
{
|
||||
type = $"NativeArray<{nativeInternalName}*>/*wahho3 class pod:{pod}*/";
|
||||
//type = $"NativeArray<{arrayApiType.FullNameNative}>/*tahho*/";
|
||||
//if (arrayTypeInfo.Type == "bool")
|
||||
// return "MUtils::ToBoolArray({0})/*bahho*/";
|
||||
if (nativeName == nativeInternalName)
|
||||
return $"MUtils::ToManagedArrayWrapperCopy<{nativeName}*>({converter})/*sahho3a*/";
|
||||
return $"MUtils::ToManagedArrayWrapperConvert<{nativeName}, {nativeInternalName}>({converter})/*sahho3b*/";
|
||||
}
|
||||
else if (nativeName == "String" || nativeName == "StringView" || nativeName == "StringAnsi")
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// Storage type should be wrapped
|
||||
type = $"NativeArray<{nativeInternalName}>/*wahho1 pod:{pod}*/";
|
||||
//type = nativeName + "*/*wahho1: {caller?.Name}*/";
|
||||
if (nativeName == nativeInternalName)
|
||||
return $"MUtils::ToManagedArrayWrapperCopy<{nativeName}>({converter})/*sahho2a*/";
|
||||
return $"MUtils::ToManagedArrayWrapperConvert<{nativeName}, {nativeInternalName}>({converter})/*sahho2b*/";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// BytesContainer
|
||||
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
{
|
||||
type = "MArray*";
|
||||
return "MUtils::ToArray({0})";
|
||||
return "/*custom: " + typeInfo.ToString() + " */MUtils::ToArray({0}, " + GenerateCppGetMClass(buildData, arrayTypeInfo, caller, functionInfo) + ")";
|
||||
}
|
||||
|
||||
// Dictionary
|
||||
@@ -692,7 +792,9 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
private static string GenerateCppWrapperManagedToNative(BuildData buildData, TypeInfo typeInfo, ApiTypeInfo caller, out string type, out ApiTypeInfo apiType, FunctionInfo functionInfo, out ParameterFormattingFlags formattingFlags)
|
||||
private static string GenerateCppWrapperManagedToNative(BuildData buildData, TypeInfo typeInfo,
|
||||
ApiTypeInfo caller, FunctionInfo functionInfo, ParameterGeneratorFlags generatorFlags, out string type,
|
||||
out ApiTypeInfo apiType, out ParameterFormattingFlags formattingFlags)
|
||||
{
|
||||
formattingFlags = ParameterFormattingFlags.None;
|
||||
|
||||
@@ -704,7 +806,7 @@ namespace Flax.Build.Bindings
|
||||
if (typeInfo.IsArray)
|
||||
{
|
||||
var arrayType = new TypeInfo { Type = "Array", GenericArgs = new List<TypeInfo> { new TypeInfo(typeInfo) { IsArray = false } } };
|
||||
var result = GenerateCppWrapperManagedToNative(buildData, arrayType, caller, out type, out _, functionInfo, out formattingFlags);
|
||||
var result = GenerateCppWrapperManagedToNative(buildData, arrayType, caller, functionInfo, generatorFlags, out type, out _, out formattingFlags);
|
||||
return result + ".Get()";
|
||||
}
|
||||
|
||||
@@ -771,7 +873,7 @@ namespace Flax.Build.Bindings
|
||||
// Array
|
||||
if (typeInfo.Type == "Array" && typeInfo.GenericArgs != null)
|
||||
{
|
||||
formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true);
|
||||
//formattingFlags.SetFlag(ParameterFormattingFlags.NeedLocalVariable, true);
|
||||
var arrayTypeInfo = typeInfo.GenericArgs[0];
|
||||
var arrayApiType = FindApiTypeInfo(buildData, arrayTypeInfo, caller);
|
||||
if (arrayApiType != null && arrayApiType.MarshalAs != null)
|
||||
@@ -791,16 +893,72 @@ namespace Flax.Build.Bindings
|
||||
genericArgs += ", " + typeInfo.GenericArgs[1];
|
||||
result = $"Array<{genericArgs}>({result})";
|
||||
}
|
||||
else if (arrayApiType?.IsPod ?? false)
|
||||
#if false
|
||||
else if (arrayApiType?.IsScriptingObject ?? false)
|
||||
{
|
||||
type = arrayApiType.FullNameNative + '*';
|
||||
result = $"Array<{genericArgs}>(({arrayApiType.FullNameNative}*){{0}}, {{1}})/*xviox1 {arrayTypeInfo.Type}*/";
|
||||
result += "/*123scriptingobject*/";
|
||||
}
|
||||
#endif
|
||||
else// if (arrayApiType?.IsValueType ?? true)
|
||||
{
|
||||
var nativeName = arrayTypeInfo.GetFullNameNative(buildData, caller);//(arrayApiType?.FullNameNative ?? arrayTypeInfo.Type);
|
||||
var nativeInternalName = nativeName;
|
||||
var converter = "{0}";
|
||||
|
||||
if (arrayApiType != null && arrayApiType.IsStruct && !arrayApiType.IsPod)
|
||||
{
|
||||
if (!CppUsedNonPodTypes.Contains(arrayApiType))
|
||||
CppUsedNonPodTypes.Add(arrayApiType);
|
||||
//pod = false;
|
||||
// Requires conversion
|
||||
//converter = "ToManaged({0})";
|
||||
//nativeInternalName = !string.IsNullOrEmpty(arrayApiType?.FullNameNativeInternal) ? arrayApiType.FullNameNativeInternal + "Managed" : null;
|
||||
nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
|
||||
//castType = nativeInternalName;
|
||||
//nativeName = nativeInternalName;
|
||||
converter = $"/*lol1*/MUtils::ToNativeArrayWrapperConvert<{nativeName}, {nativeInternalName}>(ToSpan(({{0}}).data, {{1}})).data";
|
||||
type = $"NativeArray<{nativeInternalName}>";
|
||||
result = $"Array<{genericArgs}>(/*({nativeName}*)*/{converter}, {{1}})/*456valuetype {arrayTypeInfo.Type}*/";
|
||||
}
|
||||
else if (nativeName == "String" || nativeName == "StringAnsi" || nativeName == "StringView")
|
||||
{
|
||||
//result += "/*234stringy*/";
|
||||
}
|
||||
else if (arrayTypeInfo.IsObjectRef || (arrayApiType != null && arrayApiType.IsScriptingObject))
|
||||
{
|
||||
//nativeInternalName = GenerateCppManagedWrapperName(arrayApiType);
|
||||
//castType = nativeInternalName;
|
||||
//nativeName = nativeInternalName;
|
||||
type = $"NativeArray<MObject*>";
|
||||
if (generatorFlags.HasFlag(ParameterGeneratorFlags.AssignAsReference))
|
||||
{
|
||||
converter = $"/*aar123A*/ MUtils::ToNativeArrayWrapperConvertGeneric<{genericArgs}>(ToSpan(({{0}}).data, {{1}}), {{2}})";
|
||||
result = $"{converter}/*789object {arrayTypeInfo.Type}*/";
|
||||
formattingFlags.SetFlag(ParameterFormattingFlags.AssignAsReference, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
converter = $"/*aar123B*/ MUtils::ToNativeArrayWrapperConvertGeneric<{nativeName}>(ToSpan(({{0}}).data, {{1}})).data";
|
||||
result = $"Array<{genericArgs}>({converter}, {{1}})/*678object {arrayTypeInfo.Type}*/";
|
||||
}
|
||||
formattingFlags.SetFlag(ParameterFormattingFlags.LengthParameter, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
type = $"NativeArray<{nativeInternalName}>";
|
||||
result = $"Array<{genericArgs}>(/*({nativeName}*)*/{converter}, {{1}})/*123valuetype {arrayTypeInfo.Type}*/";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#if false
|
||||
else if (arrayApiType?.Name == "bool")
|
||||
{
|
||||
throw new Exception("huh");
|
||||
type = "bool*";
|
||||
result = "Array<bool>({0}, {1})/*xviox2*/\"";
|
||||
result = "Array<bool>({0}, {1})/*123bool*/\"";
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -853,9 +1011,15 @@ namespace Flax.Build.Bindings
|
||||
// BytesContainer
|
||||
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
//formattingFlags.SetFlag(FormattingFlags.NeedLocalVariable, true);
|
||||
type = "byte*";
|
||||
return "BytesContainer({0}, {1})";
|
||||
#else
|
||||
formattingFlags.SetFlag(FormattingFlags.NeedLocalVariable, true);
|
||||
type = "MArray*";
|
||||
return "MUtils::LinkArray({0})";
|
||||
#endif
|
||||
}
|
||||
|
||||
// Function
|
||||
@@ -876,7 +1040,7 @@ namespace Flax.Build.Bindings
|
||||
if (apiType != null)
|
||||
{
|
||||
if (apiType.MarshalAs != null)
|
||||
return GenerateCppWrapperManagedToNative(buildData, apiType.MarshalAs, caller, out type, out apiType, functionInfo, out formattingFlags);
|
||||
return GenerateCppWrapperManagedToNative(buildData, apiType.MarshalAs, caller, functionInfo, generatorFlags, out type, out apiType, out formattingFlags);
|
||||
|
||||
// Scripting Object (for non-pod types converting only, other API converts managed to unmanaged object in C# wrapper code)
|
||||
if (CppNonPodTypesConvertingGeneration && apiType.IsScriptingObject && typeInfo.IsPtr)
|
||||
@@ -964,8 +1128,8 @@ namespace Flax.Build.Bindings
|
||||
return $"MUtils::ToArray({value}, {GenerateCppGetMClass(buildData, typeInfo.GenericArgs[0], caller, null)})";
|
||||
|
||||
// BytesContainer
|
||||
if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
return $"MUtils::ToArray({value})";
|
||||
//if (typeInfo.Type == "BytesContainer" && typeInfo.GenericArgs == null)
|
||||
// return $"MUtils::ToArray({value})";
|
||||
|
||||
// Construct native typename for MUtils template argument
|
||||
var nativeType = new StringBuilder(64);
|
||||
@@ -1042,6 +1206,13 @@ namespace Flax.Build.Bindings
|
||||
callerName = callerName;
|
||||
if (functionInfo.UniqueName == "SetDriveControl")
|
||||
callerName = callerName;
|
||||
if (functionInfo.UniqueName == "ProcessText2")
|
||||
callerName = callerName;
|
||||
if (functionInfo.UniqueName == "CoverageTest4")
|
||||
callerName = callerName;
|
||||
if (functionInfo.UniqueName == "SetFallbackFonts")
|
||||
callerName = callerName;
|
||||
|
||||
|
||||
// Setup function binding glue to ensure that wrapper method signature matches for C++ and C#
|
||||
functionInfo.Glue = new FunctionInfo.GlueInfo
|
||||
@@ -1055,7 +1226,9 @@ namespace Flax.Build.Bindings
|
||||
returnType = returnApiType.MarshalAs;
|
||||
|
||||
bool returnTypeIsContainer = false;
|
||||
//CppNativeArrayAsParameter = true;
|
||||
var returnValueConvert = GenerateCppWrapperNativeToManaged(buildData, functionInfo.ReturnType, caller, out var returnValueType, functionInfo);
|
||||
//CppNativeArrayAsParameter = false;
|
||||
if (functionInfo.Glue.UseReferenceForResult)
|
||||
{
|
||||
returnValueType = "void";
|
||||
@@ -1072,7 +1245,7 @@ namespace Flax.Build.Bindings
|
||||
});
|
||||
}
|
||||
#if USE_NETCORE
|
||||
else if (returnType.Type == "Array" || returnType.Type == "Span" || returnType.Type == "DataContainer" || returnType.Type == "BitArray" || returnType.Type == "BytesContainer")
|
||||
else if (returnType.IsArrayOrSpan || returnType.Type == "BitArray")
|
||||
{
|
||||
returnTypeIsContainer = true;
|
||||
functionInfo.Glue.CustomParameters.Add(new FunctionInfo.ParameterInfo
|
||||
@@ -1082,6 +1255,21 @@ namespace Flax.Build.Bindings
|
||||
Type = new TypeInfo("int"),
|
||||
IsOut = true,
|
||||
});
|
||||
|
||||
var arrayElementType = returnType.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, returnType.GenericArgs[0], caller) : null;
|
||||
if (returnType.Type == "BytesContainer" || ((arrayElementType?.IsValueType ?? true) && (arrayElementType != null && arrayElementType.MarshalAs == null)))
|
||||
{
|
||||
//returnValueConvert += ".data/*hellooy*/";
|
||||
returnValueConvert += "/*hellooy*/";
|
||||
}
|
||||
else if (arrayElementType == null)
|
||||
{
|
||||
returnValueConvert += "/*gagagaghf*/";
|
||||
}
|
||||
else
|
||||
{
|
||||
returnValueConvert += "/*BUUH*/";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1137,8 +1325,29 @@ namespace Flax.Build.Bindings
|
||||
contents.Append(", ");
|
||||
separator = true;
|
||||
|
||||
var genFlags = ParameterGeneratorFlags.None;
|
||||
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
|
||||
{
|
||||
// Special case for setters: try to set the field value via parameter reference so existing allocation in arrays can be reused.
|
||||
genFlags.SetFlag(ParameterGeneratorFlags.AssignAsReference, true);
|
||||
if (functionInfo.Parameters.Count != 1)
|
||||
separator = separator;
|
||||
}
|
||||
//else
|
||||
// genFlags.SetFlag(ParameterGeneratorFlags.AssignAsReference, true);
|
||||
|
||||
CppParamsThatNeedConversion[i] = false;
|
||||
CppParamsWrappersCache[i] = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, out var managedType, out var apiType, functionInfo, out CppParamsFormattingFlags[i]);
|
||||
//CppNativeArrayAsParameter = true;
|
||||
CppParamsWrappersCache[i] = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, functionInfo, genFlags, out var managedType, out var apiType, out CppParamsFormattingFlags[i]);
|
||||
//CppNativeArrayAsParameter = false;
|
||||
|
||||
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
|
||||
{ }
|
||||
else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Out parameters that need additional converting will be converted at the native side (eg. object reference)
|
||||
var isOutWithManagedConverter = parameterInfo.IsOut && !string.IsNullOrEmpty(GenerateCSharpManagedToNativeConverter(buildData, parameterInfo.Type, caller));
|
||||
@@ -1186,7 +1395,7 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
#if USE_NETCORE
|
||||
if (parameterInfo.Type.IsArray || parameterInfo.Type.Type == "Array" || parameterInfo.Type.Type == "Span" || parameterInfo.Type.Type == "BytesContainer" || parameterInfo.Type.Type == "DataContainer" || parameterInfo.Type.Type == "BitArray")
|
||||
if (parameterInfo.Type.IsArray || parameterInfo.Type.IsArrayOrSpan || parameterInfo.Type.Type == "BitArray")
|
||||
{
|
||||
// We need additional output parameters for array sizes
|
||||
var name = $"__{parameterInfo.Name}Count";
|
||||
@@ -1213,7 +1422,7 @@ namespace Flax.Build.Bindings
|
||||
contents.Append(", ");
|
||||
separator = true;
|
||||
|
||||
GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, out var managedType, out _, functionInfo, out _);
|
||||
GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, caller, functionInfo, ParameterGeneratorFlags.None, out var managedType, out _, out _);
|
||||
contents.Append(managedType);
|
||||
if (parameterInfo.IsRef || parameterInfo.IsOut || UsePassByReference(buildData, parameterInfo.Type, caller))
|
||||
contents.Append('*');
|
||||
@@ -1281,6 +1490,7 @@ namespace Flax.Build.Bindings
|
||||
// Call native member method
|
||||
call = $"__obj->{functionInfo.Name}";
|
||||
}
|
||||
contents.Append(indent).Append($"// convert values").AppendLine();
|
||||
string callParams = string.Empty;
|
||||
separator = false;
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
@@ -1311,12 +1521,26 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert value
|
||||
param += string.Format(CppParamsWrappersCache[i], name, countParamName);
|
||||
if (functionInfo.UniqueName == "SetFallbackFonts")
|
||||
callerName = callerName;
|
||||
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
{
|
||||
callerName = callerName;
|
||||
if (functionInfo.UniqueName.StartsWith("Set") && !functionInfo.Name.StartsWith("Set"))
|
||||
callerName = callerName; // setter
|
||||
else
|
||||
callerName = callerName;
|
||||
}
|
||||
// Convert value
|
||||
param += string.Format(CppParamsWrappersCache[i], name, countParamName, "{0}");
|
||||
}
|
||||
|
||||
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
{
|
||||
callParams += param;
|
||||
}
|
||||
// Special case for output result parameters that needs additional converting from native to managed format (such as non-POD structures or output array parameter)
|
||||
if (CppParamsThatNeedConversion[i])
|
||||
else if (CppParamsThatNeedConversion[i])
|
||||
{
|
||||
var apiType = FindApiTypeInfo(buildData, parameterInfo.Type, caller);
|
||||
if (apiType != null)
|
||||
@@ -1338,6 +1562,9 @@ namespace Flax.Build.Bindings
|
||||
callParams += "Temp";
|
||||
}
|
||||
}
|
||||
/*else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
{
|
||||
}*/
|
||||
// Special case for parameter that cannot be passed directly to the function from the wrapper method input parameter (eg. MArray* converted into BytesContainer uses as BytesContainer&)
|
||||
else if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable))
|
||||
{
|
||||
@@ -1356,9 +1583,9 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
// Non-const lvalue reference parameters needs to be passed via temporary value
|
||||
if (parameterInfo.IsOut || parameterInfo.IsRef)
|
||||
contents.Append(indent).AppendFormat("{2}& {0}Temp = {1};", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
|
||||
contents.Append(indent).AppendFormat("{2}& {0}Temp = {1}; // non-const lvalue1", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
|
||||
else
|
||||
contents.Append(indent).AppendFormat("{2} {0}Temp = {1};", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
|
||||
contents.Append(indent).AppendFormat("{2} {0}Temp = {1}; // non-const lvalue1", parameterInfo.Name, param, parameterInfo.Type.ToString(false)).AppendLine();
|
||||
callParams += parameterInfo.Name;
|
||||
callParams += "Temp";
|
||||
}
|
||||
@@ -1378,11 +1605,28 @@ namespace Flax.Build.Bindings
|
||||
contents.AppendLine();
|
||||
contents.Append(callBegin);
|
||||
}
|
||||
else if (callParams.Contains("{0}"))
|
||||
{
|
||||
if (callFormat == "{0} = {1}" && functionInfo.Parameters.Count > 0 && CppParamsFormattingFlags[0].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
{
|
||||
// Assignment is done via ref parameter
|
||||
callFormat = "{1}";
|
||||
callParams = string.Format(callParams, call);
|
||||
}
|
||||
contents.Append(indent).Append($"//callbegin123: {callFormat}").AppendLine();
|
||||
contents.Append(callBegin);
|
||||
call = string.Format(callFormat, call, callParams);
|
||||
call += "/*call123*/";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
if (callFormat == "{0} = {1}" && functionInfo.Parameters.Count > 0 && CppParamsFormattingFlags[0].HasFlag(ParameterFormattingFlags.AssignAsReference))
|
||||
callFormat = callFormat;
|
||||
contents.Append(indent).Append($"//callbegin123: {callFormat}").AppendLine();
|
||||
contents.Append(callBegin);
|
||||
call = string.Format(callFormat, call, callParams);
|
||||
call += "/*call123*/";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(returnValueConvert))
|
||||
{
|
||||
@@ -1418,6 +1662,7 @@ namespace Flax.Build.Bindings
|
||||
// Convert special parameters back to managed world
|
||||
if (!useInlinedReturn)
|
||||
{
|
||||
contents.Append(indent).Append($"// !useInlinedReturn").AppendLine();
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
{
|
||||
var parameterInfo = functionInfo.Parameters[i];
|
||||
@@ -1427,7 +1672,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
var value = string.Format(CppParamsThatNeedConversionWrappers[i], parameterInfo.Name + "Temp");
|
||||
var elementType = parameterInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], caller) : null;
|
||||
|
||||
var convertedType = CppParamsThatNeedConversionTypes[i];
|
||||
// MObject* parameters returned by reference need write barrier for GC
|
||||
if (parameterInfo.IsOut)
|
||||
{
|
||||
@@ -1439,17 +1684,24 @@ namespace Flax.Build.Bindings
|
||||
#if USE_NETCORE
|
||||
if (parameterInfo.Type.Type == "Array")
|
||||
{
|
||||
if (elementType?.IsPod ?? false)
|
||||
//if (elementType?.IsPod ?? true)
|
||||
{
|
||||
contents.Append(indent).Append($"// isgigs1a").AppendLine();
|
||||
contents.Append(indent).Append($"*{parameterInfo.Name} = ({parameterInfo.Type.GenericArgs[0]}*)MCore::GC::AllocateMemory(sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
|
||||
contents.Append(indent).Append($"Platform::MemoryCopy(*{parameterInfo.Name}, {parameterInfo.Name}Temp.Get(), sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
|
||||
var nativeType = elementType?.FullNameNative;
|
||||
var internalType = elementType?.FullNameNativeInternal;
|
||||
contents.Append(indent).Append($"// isgigs1a, {elementType?.ToString()}, native: {nativeType}, internal: {internalType}, value: {value}").AppendLine();
|
||||
contents.Append(indent).Append($"*{parameterInfo.Name} = {value};").AppendLine();
|
||||
/*if (string.IsNullOrEmpty(internalType) || nativeType == internalType)
|
||||
contents.Append(indent).Append($"*{parameterInfo.Name} = MUtils::ToNativeArrayWrapper<{nativeType}>(ToSpan({parameterInfo.Name}Temp));").AppendLine();
|
||||
else
|
||||
contents.Append(indent).Append($"*{parameterInfo.Name} = MUtils::ToNativeArrayWrapper<{nativeType}, {internalType}>(ToSpan({parameterInfo.Name}Temp));").AppendLine();*/
|
||||
//contents.Append(indent).Append($"*{parameterInfo.Name} = ({parameterInfo.Type.GenericArgs[0]}*)MCore::GC::AllocateMemory(sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
|
||||
//contents.Append(indent).Append($"Platform::MemoryCopy(*{parameterInfo.Name}, {parameterInfo.Name}Temp.Get(), sizeof({parameterInfo.Type.GenericArgs[0]}) * {parameterInfo.Name}Temp.Count());").AppendLine();
|
||||
}
|
||||
else
|
||||
/*else
|
||||
{
|
||||
contents.Append(indent).Append($"// isgigs1b").AppendLine();
|
||||
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
|
||||
}
|
||||
}*/
|
||||
|
||||
// Array marshallers need to know amount of items written in the buffer
|
||||
contents.Append(indent).AppendFormat("*__{0}Count = {1}.Count();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
|
||||
@@ -1475,20 +1727,24 @@ namespace Flax.Build.Bindings
|
||||
// BytesContainer
|
||||
if (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null)
|
||||
{
|
||||
#if USE_NETCORE
|
||||
contents.Append(indent).AppendFormat("*{0} = {1}; //123bytescontainerout", parameterInfo.Name, value).AppendLine();
|
||||
#else
|
||||
contents.Append(indent).Append($"// hshsf").AppendLine();
|
||||
contents.Append(indent).AppendFormat("MCore::GC::WriteRef({0}, (MObject*){1});", parameterInfo.Name, value).AppendLine();
|
||||
|
||||
// Array marshallers need to know amount of items written in the buffer
|
||||
//contents.Append(indent).AppendFormat("*__{0}Count = {1}.Length();", parameterInfo.Name, parameterInfo.Name + "Temp").AppendLine();
|
||||
//continue;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
throw new Exception($"Unsupported type of parameter '{parameterInfo}' in method '{functionInfo}' to be passed using 'out'");
|
||||
}
|
||||
}
|
||||
else if (parameterInfo.Type.Type == "Array" && (elementType?.IsPod ?? false))
|
||||
/*else if (parameterInfo.Type.Type == "Array" && (elementType?.IsPod ?? false))
|
||||
contents.Append(indent).AppendFormat("*{0} = {1}.data;", parameterInfo.Name, value).AppendLine();
|
||||
else
|
||||
else*/
|
||||
contents.Append(indent).AppendFormat("*{0} = {1};", parameterInfo.Name, value).AppendLine();
|
||||
#if USE_NETCORE
|
||||
if (parameterInfo.Type.Type == "Array" || (parameterInfo.Type.Type == "BytesContainer" && parameterInfo.Type.GenericArgs == null))
|
||||
@@ -1569,6 +1825,9 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
if (!EngineConfiguration.WithCSharp(buildData.TargetOptions))
|
||||
return;
|
||||
if (functionInfo.UniqueName == "CoverageTest1ByRef")
|
||||
scriptVTableSize = scriptVTableSize;
|
||||
|
||||
contents.AppendFormat(" {0} {1}_ManagedWrapper(", functionInfo.ReturnType, functionInfo.UniqueName);
|
||||
var separator = false;
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
@@ -1637,7 +1896,7 @@ namespace Flax.Build.Bindings
|
||||
|
||||
// If platform supports JITed code execution then use method thunk, otherwise fallback to generic runtime invoke
|
||||
var returnType = functionInfo.ReturnType;
|
||||
var useThunk = buildData.Platform.HasDynamicCodeExecutionSupport && Configuration.AOTMode == DotNetAOTModes.None;
|
||||
var useThunk = false;//buildData.Platform.HasDynamicCodeExecutionSupport && Configuration.AOTMode == DotNetAOTModes.None;
|
||||
if (useThunk)
|
||||
{
|
||||
//contents.AppendLine($" PROFILE_CPU_NAMED(\"{classInfo.FullNameManaged}::{functionInfo.Name}\");");
|
||||
@@ -1658,6 +1917,7 @@ namespace Flax.Build.Bindings
|
||||
if (paramIsRef)
|
||||
{
|
||||
// Pass as pointer to value when using ref/out parameter
|
||||
contents.Append($" localvar2 // {apiType.FullNameNative}").AppendLine();
|
||||
contents.Append($" auto __param_orig_{parameterInfo.Name} = {paramValue};").AppendLine();
|
||||
contents.Append($" auto __param_{parameterInfo.Name} = __param_orig_{parameterInfo.Name};").AppendLine();
|
||||
paramValue = $"&__param_{parameterInfo.Name}";
|
||||
@@ -1719,6 +1979,7 @@ namespace Flax.Build.Bindings
|
||||
// Invoke method
|
||||
contents.AppendLine(" MObject* __result = method->Invoke(object->GetOrCreateManagedInstance(), params, &exception);");
|
||||
|
||||
contents.AppendLine(" // convert to native");
|
||||
// Convert parameter values back from managed to native (could be modified there)
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
{
|
||||
@@ -1726,15 +1987,16 @@ namespace Flax.Build.Bindings
|
||||
if ((parameterInfo.IsRef || parameterInfo.IsOut) && !parameterInfo.Type.IsConst)
|
||||
{
|
||||
// Direct value convert
|
||||
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, out var managedType, out var apiType, null, out _);
|
||||
var passAsParamPtr = managedType.EndsWith("*");
|
||||
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
|
||||
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
|
||||
var paramName = CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable) ? $"__param_{parameterInfo.Name}" : $"params[{i}]";
|
||||
var managedToNative = GenerateCppWrapperManagedToNative(buildData, parameterInfo.Type, classInfo, null, ParameterGeneratorFlags.None, out var managedType, out var apiType, out _);
|
||||
var passAsParamPtr = managedType.EndsWith("*") || true;
|
||||
var useLocalVarPointer = !CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable);
|
||||
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)&{paramName}" : paramName;
|
||||
if (!string.IsNullOrEmpty(managedToNative))
|
||||
{
|
||||
if (!passAsParamPtr)
|
||||
paramValue = '*' + paramValue;
|
||||
paramValue = string.Format(managedToNative, paramValue);
|
||||
paramValue = string.Format(managedToNative, paramValue, $"__param_{parameterInfo.Name}.length");
|
||||
}
|
||||
else if (!passAsParamPtr)
|
||||
paramValue = '*' + paramValue;
|
||||
@@ -1761,12 +2023,18 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
}
|
||||
|
||||
// Release GCHandles of boxed values
|
||||
// Release temporary managed resources
|
||||
for (var i = 0; i < functionInfo.Parameters.Count; i++)
|
||||
{
|
||||
var parameterInfo = functionInfo.Parameters[i];
|
||||
var paramValue = GenerateCppWrapperNativeToBox(buildData, parameterInfo.Type, classInfo, out var apiType, parameterInfo.Name);
|
||||
var paramIsRef = parameterInfo.IsRef || parameterInfo.IsOut;
|
||||
var paramIsValueType = apiType?.IsValueType ?? true;
|
||||
var elementApiType = apiType != null && parameterInfo.Type.GenericArgs?.Count > 0 ? FindApiTypeInfo(buildData, parameterInfo.Type.GenericArgs[0], apiType) : null;
|
||||
var elementIsValueType = elementApiType?.IsValueType ?? true;
|
||||
var elementIsClass = elementApiType?.IsClass ?? false;
|
||||
var elementIsPod = elementApiType?.IsPod ?? true;
|
||||
var elementIsObject = (parameterInfo.Type.GenericArgs?[0].IsObjectRef ?? false) || (elementApiType?.IsScriptingObject ?? false);
|
||||
|
||||
if (paramValue.Contains("MUtils::Box<")) // FIXME
|
||||
{
|
||||
@@ -1779,31 +2047,44 @@ namespace Flax.Build.Bindings
|
||||
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine();
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
|
||||
}*/
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
|
||||
if (useThunk)
|
||||
|
||||
//var ispod = parameterInfo.Type.IsPod(buildData, apiType);
|
||||
//contents.Append($" // {parameterInfo.Type.Type} is pod: {ispod}||{apiType.IsPod}, valuetype: {apiType.IsValueType}, classtype: {apiType.IsClass} // doerp1").AppendLine();
|
||||
if (useThunk || !paramIsValueType)
|
||||
{
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_{parameterInfo.Name}); // darr1").AppendLine();
|
||||
// Release the original handle
|
||||
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine();
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)__param_orig_{parameterInfo.Name});").AppendLine();
|
||||
}
|
||||
else if (paramIsValueType)
|
||||
{
|
||||
contents.Append($" //durr2").AppendLine();
|
||||
|
||||
}
|
||||
else if (CppParamsThatNeedConversion[i])
|
||||
{
|
||||
contents.Append($" FreeManaged(__param_{parameterInfo.Name}); //durr1").AppendLine();
|
||||
}
|
||||
}
|
||||
else if (apiType != null && !apiType.IsInBuild)
|
||||
{
|
||||
// int: ispod, isvaluetype
|
||||
// vector: ispod, isvaluetype, isstruct
|
||||
// guid: ispod, isvaluetype, isstruct, isinbuild
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1b").AppendLine();
|
||||
if (useThunk || !paramIsValueType)
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1b").AppendLine();
|
||||
//contents.Append($" auto __param{i}_handle = *(MGCHandle*)¶ms[{i}]; // asdf1b").AppendLine();
|
||||
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
|
||||
//contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
|
||||
}
|
||||
else if (apiType != null && !apiType.IsValueType)
|
||||
else if (apiType != null && !paramIsValueType)
|
||||
{
|
||||
if (parameterInfo.Type.Type.ToLower().Contains("string"))
|
||||
apiType = apiType;
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.Type}>((MObject*)params[{i}]); //asdf1d").AppendLine();
|
||||
}
|
||||
else //if (apiType != null)
|
||||
else if (useThunk)//if (apiType != null)
|
||||
{
|
||||
if (parameterInfo.Type.Type.ToLower().Contains("string"))
|
||||
apiType = apiType;
|
||||
@@ -1815,9 +2096,17 @@ namespace Flax.Build.Bindings
|
||||
}
|
||||
else if (paramValue.Contains("MUtils::ToArray(")) // FIXME
|
||||
{
|
||||
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
|
||||
if (paramIsRef)
|
||||
if (parameterInfo.Type.Type == "BytesContainer")
|
||||
{
|
||||
if (useThunk)
|
||||
contents.Append($" MUtils::FreeManagedArray<byte>((MArray*)params[{i}]); //fgfgh8").AppendLine();
|
||||
else
|
||||
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //fgfghdf8").AppendLine();
|
||||
//contents.Append($" MUtils::FreeManagedArray<byte>((MArray*)params[{i}]); //fgfgh8").AppendLine();
|
||||
}
|
||||
else if (paramIsRef)
|
||||
{
|
||||
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
|
||||
//contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
|
||||
/*if (useThunk)
|
||||
{
|
||||
@@ -1825,16 +2114,41 @@ namespace Flax.Build.Bindings
|
||||
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{parameterInfo.Name}) //asdf1a").AppendLine();
|
||||
contents.Append($" MUtils::FreeManaged<{parameterInfo.Type.ToString(false)}>((MObject*)__param_{parameterInfo.Name});").AppendLine();
|
||||
}*/
|
||||
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_{parameterInfo.Name}); //fgfgh3").AppendLine();
|
||||
if (useThunk)
|
||||
|
||||
//var isPod = parameterInfo.Type.GenericArgs.Count > 0 ? parameterInfo.Type.GenericArgs[0].IsPod(buildData, apiType) : false;
|
||||
contents.Append($" // {parameterInfo.Type} is pod: {elementApiType?.IsPod}, valuetype: {paramIsValueType}, classtype: {apiType.IsClass} // huah").AppendLine();
|
||||
if (useThunk /*|| CppParamsThatNeedConversion[i]*/ || genericType == "String" || genericType == "StringAnsi" || genericType == "StringView")
|
||||
{
|
||||
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_{parameterInfo.Name}); //fgfgh3").AppendLine();
|
||||
|
||||
// Release the original handle
|
||||
contents.Append($" if (__param_orig_{parameterInfo.Name} != __param_{ parameterInfo.Name})").AppendLine();
|
||||
contents.Append($" MUtils::FreeManagedArray<{genericType}>(__param_orig_{parameterInfo.Name}); //fgfgh4").AppendLine();
|
||||
}
|
||||
/*else if (elementIsValueType)
|
||||
{
|
||||
contents.Append($" // huhhah free").AppendLine();
|
||||
}*/
|
||||
else// if (CppParamsThatNeedConversion[i])
|
||||
{
|
||||
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //jfgfgh7").AppendLine();
|
||||
|
||||
// Release the original handle
|
||||
contents.Append($" if (__param_orig_{parameterInfo.Name}.data != __param_{parameterInfo.Name}.data)").AppendLine();
|
||||
contents.Append($" MCore::GC::FreeMemory(__param_orig_{parameterInfo.Name}.data, true); //fgfgh8").AppendLine();
|
||||
}
|
||||
}
|
||||
else if (elementApiType?.IsPod ?? false)
|
||||
{
|
||||
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
|
||||
if (CppParamsFormattingFlags[i].HasFlag(ParameterFormattingFlags.NeedLocalVariable))
|
||||
contents.Append($" MCore::GC::FreeMemory(__param_{parameterInfo.Name}.data, true); //kfgfgh7a").AppendLine();
|
||||
else
|
||||
contents.Append($" MCore::GC::FreeMemory(params[{i}], true); //kfgfgh7b").AppendLine();
|
||||
}
|
||||
else if (apiType != null && !apiType.IsInBuild)
|
||||
{
|
||||
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
|
||||
// int: ispod, isvaluetype
|
||||
// vector: ispod, isvaluetype, isstruct
|
||||
// guid: ispod, isvaluetype, isstruct, isinbuild
|
||||
@@ -1843,8 +2157,9 @@ namespace Flax.Build.Bindings
|
||||
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
|
||||
//contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
|
||||
}
|
||||
else if (apiType != null && !apiType.IsValueType)
|
||||
else if (apiType != null && !paramIsValueType)
|
||||
{
|
||||
var genericType = parameterInfo.Type.GenericArgs[0].ToString(false);
|
||||
if (parameterInfo.Type.Type.ToLower().Contains("string"))
|
||||
apiType = apiType;
|
||||
contents.Append($" MUtils::FreeManagedArray<{genericType}>((MArray*)params[{i}]); //fgfgh6").AppendLine();
|
||||
@@ -1854,7 +2169,7 @@ namespace Flax.Build.Bindings
|
||||
if (parameterInfo.Type.Type.ToLower().Contains("string"))
|
||||
apiType = apiType;
|
||||
//contents.Append($" //asdf1c {parameterInfo.Type.Type}").AppendLine();
|
||||
contents.Append($" auto __param{i}_handle = *(MGCHandle*)¶ms[{i}]; //fgfgh7").AppendLine();
|
||||
contents.Append($" auto __param{i}_handle = *(MGCHandle*)¶ms[{i}]; //nfgfgh7").AppendLine();
|
||||
//contents.Append($" ASSERT((((unsigned long long)__param{i}_handle & 0xC000000000000000) >> 62) == 0);").AppendLine();
|
||||
contents.Append($" MCore::GCHandle::Free(__param{i}_handle);").AppendLine();
|
||||
}
|
||||
@@ -2299,7 +2614,7 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
// Convert value back from managed to native (could be modified there)
|
||||
paramType.IsRef = false;
|
||||
var managedToNative = GenerateCppWrapperManagedToNative(buildData, paramType, classInfo, out var managedType, out var apiType, null, out _);
|
||||
var managedToNative = GenerateCppWrapperManagedToNative(buildData, paramType, classInfo, null, ParameterGeneratorFlags.None, out var managedType, out var apiType, out _);
|
||||
var passAsParamPtr = managedType.EndsWith("*");
|
||||
var useLocalVarPointer = CppParamsThatNeedConversion[i] && !apiType.IsValueType;
|
||||
var paramValue = useLocalVarPointer ? $"*({managedType}{(passAsParamPtr ? "" : "*")}*)params[{i}]" : $"({managedType}{(passAsParamPtr ? "" : "*")})params[{i}]";
|
||||
@@ -3231,7 +3546,9 @@ namespace Flax.Build.Bindings
|
||||
continue;
|
||||
}
|
||||
|
||||
//CppNativeArrayAsParameter = true;
|
||||
CppParamsWrappersCache[i] = GenerateCppWrapperNativeToManaged(buildData, fieldInfo.Type, apiType, out type, null);
|
||||
//CppNativeArrayAsParameter = false;
|
||||
header.AppendFormat(" {0} {1};", type, fieldInfo.Name).AppendLine();
|
||||
}
|
||||
header.Append('}').Append(';').AppendLine();
|
||||
@@ -3251,7 +3568,7 @@ namespace Flax.Build.Bindings
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED MObject* Box(const {0}& data, const MClass* klass)", fullName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
header.Append(" auto managed = ToManaged(data);").AppendLine();
|
||||
header.Append(" auto managed = ::ToManaged(data);").AppendLine();
|
||||
header.Append(" auto boxed = MCore::Object::Box((void*)&managed, klass);").AppendLine();
|
||||
header.Append(" ::FreeManaged(managed);").AppendLine();
|
||||
header.Append(" return boxed;").AppendLine();
|
||||
@@ -3262,7 +3579,7 @@ namespace Flax.Build.Bindings
|
||||
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
|
||||
header.AppendFormat(" {0} managed;", wrapperName).AppendLine();
|
||||
header.Append(" MCore::Object::Unbox(data, &managed);").AppendLine();
|
||||
header.Append(" result = ToNative(managed);").AppendLine();
|
||||
header.Append(" result = ::ToNative(managed);").AppendLine();
|
||||
header.Append(" ::FreeManaged(managed);").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
@@ -3272,7 +3589,7 @@ namespace Flax.Build.Bindings
|
||||
header.AppendFormat(" {0}* resultPtr = ({0}*)MCore::Array::GetAddress(result);", wrapperName).AppendLine();
|
||||
header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
header.Append(" auto managed = ToManaged(data[i]);").AppendLine();
|
||||
header.Append(" auto managed = ::ToManaged(data[i]);").AppendLine();
|
||||
header.Append(" MCore::GC::WriteValue(&resultPtr[i], &managed, 1, klass);").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
@@ -3281,7 +3598,7 @@ namespace Flax.Build.Bindings
|
||||
header.Append(" {").AppendLine();
|
||||
header.AppendFormat(" {0}* dataPtr = ({0}*)MCore::Array::GetAddress(data);", wrapperName).AppendLine();
|
||||
header.Append(" for (int32 i = 0; i < result.Length(); i++)").AppendLine();
|
||||
header.Append(" result[i] = ToNative(dataPtr[i]);").AppendLine();
|
||||
header.Append(" result[i] = ::ToNative(dataPtr[i]);").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void FreeManaged(MObject* data)").AppendLine();
|
||||
@@ -3311,6 +3628,27 @@ namespace Flax.Build.Bindings
|
||||
|
||||
header.Append('}').Append(';').AppendLine();
|
||||
|
||||
// Generate MConverter for a structure
|
||||
header.Append("template<>").AppendLine();
|
||||
header.AppendFormat("struct MConverter<{0}, {1}>", fullName, wrapperName).AppendLine();
|
||||
header.Append('{').AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void ToManaged({1}& result, const {0}& data) const /*struct*/", fullName, wrapperName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
|
||||
//header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
|
||||
header.Append(" result = ::ToManaged(data);").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void ToNative({0}& result, const {1}& data) const", fullName, wrapperName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
|
||||
//header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
|
||||
header.Append(" result = ::ToNative(data);").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.Append('}').Append(';').AppendLine();
|
||||
|
||||
// Generate converting function native -> managed
|
||||
header.AppendLine();
|
||||
header.AppendLine("namespace {");
|
||||
@@ -3356,7 +3694,7 @@ namespace Flax.Build.Bindings
|
||||
continue;
|
||||
|
||||
CppNonPodTypesConvertingGeneration = true;
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var fieldTypeName, out var fieldType, null, out _);
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var fieldTypeName, out var fieldType, out _);
|
||||
CppNonPodTypesConvertingGeneration = false;
|
||||
|
||||
var arrayCountName = $"value.{fieldInfo.Name}.length";
|
||||
@@ -3387,15 +3725,12 @@ namespace Flax.Build.Bindings
|
||||
{
|
||||
var arrayElementType = fieldInfo.Type.GenericArgs != null ? FindApiTypeInfo(buildData, fieldInfo.Type.GenericArgs[0], apiType) : null;
|
||||
var ispod = (arrayElementType?.IsPod.ToString() ?? "null");
|
||||
header.Append($" // {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
|
||||
if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsPod ?? false))
|
||||
header.Append($" // pluh: {fieldInfo.Type.Type}, {fieldType?.FullNameNative}, {fieldType?.Name}, {fieldTypeName}, {ispod}").AppendLine();
|
||||
//if (fieldInfo.Type.IsArrayOrSpan && (arrayElementType?.IsValueType ?? false))
|
||||
{
|
||||
header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}.data", $"value.{fieldInfo.Name}.length")).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
header.AppendFormat(" result.{0} = {1}; /*kaek2 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.lengthnot")).AppendLine();
|
||||
header.AppendFormat(" result.{0} = {1}; /*kaek1 */", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}", $"value.{fieldInfo.Name}.length")).AppendLine();
|
||||
}
|
||||
|
||||
//var fieldType = FindApiTypeInfo(buildData, fieldInfo.Type, apiType);
|
||||
|
||||
//header.AppendFormat(" result.{0} = {1}; /*kaek2*/", fieldInfo.Name, string.Format(wrapper, $"value.{fieldInfo.Name}")).AppendLine();
|
||||
@@ -3421,7 +3756,7 @@ namespace Flax.Build.Bindings
|
||||
continue;
|
||||
|
||||
CppNonPodTypesConvertingGeneration = true;
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var managedType, out var fieldApiType, null, out _);
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var managedType, out var fieldApiType, out _);
|
||||
CppNonPodTypesConvertingGeneration = false;
|
||||
|
||||
if (fieldInfo.Type.IsArray)
|
||||
@@ -3558,7 +3893,7 @@ namespace Flax.Build.Bindings
|
||||
continue;
|
||||
|
||||
CppNonPodTypesConvertingGeneration = true;
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, out var type, out _, null, out _);
|
||||
var wrapper = GenerateCppWrapperManagedToNative(buildData, fieldInfo.Type, apiType, null, ParameterGeneratorFlags.None, out var type, out _, out _);
|
||||
CppNonPodTypesConvertingGeneration = false;
|
||||
|
||||
CppIncludeFiles.Add("Engine/Scripting/ManagedCLR/MField.h");
|
||||
@@ -3576,6 +3911,18 @@ namespace Flax.Build.Bindings
|
||||
header.Append(" return result;").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void ToManaged({1}& result, const {0}& data) const /*class*/", fullName, fullName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
|
||||
header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void ToNative({0}& result, const {1}& data) const", fullName, fullName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
//header.AppendFormat(" result = ToNative(*reinterpret_cast<{0}*>(MCore::Object::Unbox(data)));", wrapperName).AppendLine();
|
||||
header.Append(" PLATFORM_DEBUG_BREAK;").AppendLine();
|
||||
header.Append(" }").AppendLine();
|
||||
|
||||
header.AppendFormat(" DLLEXPORT USED void ToManagedArray(MArray* result, const Span<{0}>& data)", fullName).AppendLine();
|
||||
header.Append(" {").AppendLine();
|
||||
header.Append(" for (int32 i = 0; i < data.Length(); i++)").AppendLine();
|
||||
|
||||
@@ -487,6 +487,10 @@ namespace Flax.Build.Platforms
|
||||
}
|
||||
commonArgs.Add("/Zc:__cplusplus");
|
||||
|
||||
// Strict standards conformance mode
|
||||
commonArgs.Add("/permissive-");
|
||||
commonArgs.Add("/Zc:externC-"); // Required for WindowsMinimal.h
|
||||
|
||||
// Generate Intrinsic Functions
|
||||
if (compileEnvironment.IntrinsicFunctions)
|
||||
commonArgs.Add("/Oi");
|
||||
|
||||
@@ -204,7 +204,7 @@ namespace Flax.Build.Projects.VisualStudio
|
||||
var filePath = file.Replace('/', '\\'); // Normalize path
|
||||
var projectPath = Utilities.MakePathRelativeTo(filePath, projectDirectory);
|
||||
string linkPath = null;
|
||||
if (!filePath.StartsWith(rootPath))
|
||||
if (!filePath.StartsWith(rootPath)) // TODO: FIXME for FlaxEngine project in game solutions
|
||||
{
|
||||
// Create folder structure for project external files
|
||||
var sourceIndex = filePath.LastIndexOf(@"\Source\");
|
||||
|
||||
Reference in New Issue
Block a user